You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2026-05-22 10:15:16 +02:00
Move coverage code to CoverageTest module.
This code needs some work, which will be easier if it is all in one place.
This commit is contained in:
@@ -22,6 +22,12 @@ use pgBackRestDoc::Html::DocHtmlBuilder;
|
|||||||
use pgBackRestDoc::Html::DocHtmlElement;
|
use pgBackRestDoc::Html::DocHtmlElement;
|
||||||
use pgBackRestDoc::ProjectInfo;
|
use pgBackRestDoc::ProjectInfo;
|
||||||
|
|
||||||
|
use pgBackRestTest::Common::ContainerTest;
|
||||||
|
use pgBackRestTest::Common::DefineTest;
|
||||||
|
use pgBackRestTest::Common::ExecuteTest;
|
||||||
|
use pgBackRestTest::Common::ListTest;
|
||||||
|
use pgBackRestTest::Common::RunTest;
|
||||||
|
|
||||||
####################################################################################################################################
|
####################################################################################################################################
|
||||||
# Generate an lcov configuration file
|
# Generate an lcov configuration file
|
||||||
####################################################################################################################################
|
####################################################################################################################################
|
||||||
@@ -66,6 +72,297 @@ sub coverageLCovConfigGenerate
|
|||||||
|
|
||||||
push @EXPORT, qw(coverageLCovConfigGenerate);
|
push @EXPORT, qw(coverageLCovConfigGenerate);
|
||||||
|
|
||||||
|
####################################################################################################################################
|
||||||
|
# Extract coverage using gcov
|
||||||
|
####################################################################################################################################
|
||||||
|
sub coverageExtract
|
||||||
|
{
|
||||||
|
my $oStorage = shift;
|
||||||
|
my $strModule = shift;
|
||||||
|
my $strTest = shift;
|
||||||
|
my $bSummary = shift;
|
||||||
|
my $strContainerImage = shift;
|
||||||
|
my $strWorkPath = shift;
|
||||||
|
my $strWorkTmpPath = shift;
|
||||||
|
my $strWorkUnitPath = shift;
|
||||||
|
my $strTestResultCoveragePath = shift . '/coverage';
|
||||||
|
|
||||||
|
# Generate a list of files to cover
|
||||||
|
my $hTestCoverage = (testDefModuleTest($strModule, $strTest))->{&TESTDEF_COVERAGE};
|
||||||
|
|
||||||
|
my @stryCoveredModule;
|
||||||
|
|
||||||
|
foreach my $strModule (sort(keys(%{$hTestCoverage})))
|
||||||
|
{
|
||||||
|
push (@stryCoveredModule, $strModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
push(@stryCoveredModule, "module/${strModule}/" . testRunName($strTest, false) . 'Test');
|
||||||
|
|
||||||
|
# Generate coverage reports for the modules
|
||||||
|
my $strLCovConf = "${strTestResultCoveragePath}/raw/lcov.conf";
|
||||||
|
coverageLCovConfigGenerate($oStorage, $strLCovConf, $bSummary);
|
||||||
|
|
||||||
|
my $strLCovExeBase = "lcov --config-file=${strLCovConf}";
|
||||||
|
my $strLCovOut = "${strWorkUnitPath}/test.lcov";
|
||||||
|
my $strLCovOutTmp = "${strWorkUnitPath}/test.tmp.lcov";
|
||||||
|
|
||||||
|
executeTest(
|
||||||
|
(defined($strContainerImage) ? 'docker exec -i -u ' . TEST_USER . " ${strContainerImage} " : '') .
|
||||||
|
"${strLCovExeBase} --capture --directory=${strWorkUnitPath} --o=${strLCovOut}");
|
||||||
|
|
||||||
|
# Generate coverage report for each module
|
||||||
|
foreach my $strCoveredModule (@stryCoveredModule)
|
||||||
|
{
|
||||||
|
my $strModuleName = testRunName($strCoveredModule, false);
|
||||||
|
my $strModuleOutName = $strModuleName;
|
||||||
|
my $bTest = false;
|
||||||
|
|
||||||
|
if ($strModuleOutName =~ /^module/mg)
|
||||||
|
{
|
||||||
|
$strModuleOutName =~ s/^module/test/mg;
|
||||||
|
$bTest = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Disable branch coverage for test files
|
||||||
|
my $strLCovExe = $strLCovExeBase;
|
||||||
|
|
||||||
|
if ($bTest)
|
||||||
|
{
|
||||||
|
$strLCovExe .= ' --rc lcov_branch_coverage=0';
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate lcov reports
|
||||||
|
my $strModulePath =
|
||||||
|
"${strWorkPath}/repo/" .
|
||||||
|
(${strModuleOutName} =~ /^test\// ?
|
||||||
|
'test/src/module/' . substr(${strModuleOutName}, 5) : "src/${strModuleOutName}");
|
||||||
|
my $strLCovFile = "${strTestResultCoveragePath}/raw/${strModuleOutName}.lcov";
|
||||||
|
my $strLCovTotal = "${strWorkTmpPath}/all.lcov";
|
||||||
|
|
||||||
|
executeTest(
|
||||||
|
"${strLCovExe} --extract=${strLCovOut} */${strModuleName}.c --o=${strLCovOutTmp}");
|
||||||
|
|
||||||
|
# Combine with prior run if there was one
|
||||||
|
if ($oStorage->exists($strLCovFile))
|
||||||
|
{
|
||||||
|
my $strCoverage = ${$oStorage->get($strLCovOutTmp)};
|
||||||
|
$strCoverage =~ s/^SF\:.*$/SF:$strModulePath\.c/mg;
|
||||||
|
$oStorage->put($strLCovOutTmp, $strCoverage);
|
||||||
|
|
||||||
|
executeTest(
|
||||||
|
"${strLCovExe} --add-tracefile=${strLCovOutTmp} --add-tracefile=${strLCovFile} --o=${strLCovOutTmp}");
|
||||||
|
}
|
||||||
|
|
||||||
|
# Update source file
|
||||||
|
my $strCoverage = ${$oStorage->get($strLCovOutTmp)};
|
||||||
|
|
||||||
|
if (defined($strCoverage))
|
||||||
|
{
|
||||||
|
if (!$bTest && $hTestCoverage->{$strCoveredModule} eq TESTDEF_COVERAGE_NOCODE)
|
||||||
|
{
|
||||||
|
confess &log(ERROR, "module '${strCoveredModule}' is marked 'no code' but has code");
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get coverage info
|
||||||
|
my $iTotalLines = (split(':', ($strCoverage =~ m/^LF:.*$/mg)[0]))[1] + 0;
|
||||||
|
my $iCoveredLines = (split(':', ($strCoverage =~ m/^LH:.*$/mg)[0]))[1] + 0;
|
||||||
|
|
||||||
|
my $iTotalBranches = 0;
|
||||||
|
my $iCoveredBranches = 0;
|
||||||
|
|
||||||
|
if ($strCoverage =~ /^BRF\:/mg && $strCoverage =~ /^BRH\:/mg)
|
||||||
|
{
|
||||||
|
# If this isn't here the statements below fail -- huh?
|
||||||
|
my @match = $strCoverage =~ m/^BRF\:.*$/mg;
|
||||||
|
|
||||||
|
$iTotalBranches = (split(':', ($strCoverage =~ m/^BRF:.*$/mg)[0]))[1] + 0;
|
||||||
|
$iCoveredBranches = (split(':', ($strCoverage =~ m/^BRH:.*$/mg)[0]))[1] + 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Report coverage if this is not a test or if the test does not have complete coverage
|
||||||
|
if (!$bTest || $iTotalLines != $iCoveredLines || $iTotalBranches != $iCoveredBranches)
|
||||||
|
{
|
||||||
|
# Fix source file name
|
||||||
|
$strCoverage =~ s/^SF\:.*$/SF:$strModulePath\.c/mg;
|
||||||
|
|
||||||
|
$oStorage->put($oStorage->openWrite($strLCovFile, {bPathCreate => true}), $strCoverage);
|
||||||
|
|
||||||
|
if ($oStorage->exists($strLCovTotal))
|
||||||
|
{
|
||||||
|
executeTest("${strLCovExe} --add-tracefile=${strLCovFile} --add-tracefile=${strLCovTotal} --o=${strLCovTotal}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$oStorage->copy($strLCovFile, $strLCovTotal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$oStorage->remove($strLCovFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($hTestCoverage->{$strCoveredModule} ne TESTDEF_COVERAGE_NOCODE)
|
||||||
|
{
|
||||||
|
confess &log(ERROR, "module '${strCoveredModule}' is marked 'code' but has no code");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
push @EXPORT, qw(coverageExtract);
|
||||||
|
|
||||||
|
####################################################################################################################################
|
||||||
|
# Validate converage and generate reports
|
||||||
|
####################################################################################################################################
|
||||||
|
sub coverageValidateAndGenerate
|
||||||
|
{
|
||||||
|
my $oyTestRun = shift;
|
||||||
|
my $oStorage = shift;
|
||||||
|
my $bCoverageSummary = shift;
|
||||||
|
my $strWorkTmpPath = shift;
|
||||||
|
my $strTestResultCoveragePath = shift . '/coverage';
|
||||||
|
my $strTestResultSummaryPath = shift;
|
||||||
|
|
||||||
|
my $result = 0;
|
||||||
|
|
||||||
|
# Determine which modules were covered (only check coverage if all tests were successful)
|
||||||
|
#-----------------------------------------------------------------------------------------------------------------------
|
||||||
|
my $hModuleTest; # Everything that was run
|
||||||
|
|
||||||
|
# Build a hash of all modules, tests, and runs that were executed
|
||||||
|
foreach my $hTestRun (@{$oyTestRun})
|
||||||
|
{
|
||||||
|
# Get coverage for the module
|
||||||
|
my $strModule = $hTestRun->{&TEST_MODULE};
|
||||||
|
my $hModule = testDefModule($strModule);
|
||||||
|
|
||||||
|
# Get coverage for the test
|
||||||
|
my $strTest = $hTestRun->{&TEST_NAME};
|
||||||
|
my $hTest = testDefModuleTest($strModule, $strTest);
|
||||||
|
|
||||||
|
# If no tests are listed it means all of them were run
|
||||||
|
if (@{$hTestRun->{&TEST_RUN}} == 0)
|
||||||
|
{
|
||||||
|
$hModuleTest->{$strModule}{$strTest} = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Now compare against code modules that should have full coverage
|
||||||
|
my $hCoverageList = testDefCoverageList();
|
||||||
|
my $hCoverageType = testDefCoverageType();
|
||||||
|
my $hCoverageActual;
|
||||||
|
|
||||||
|
foreach my $strCodeModule (sort(keys(%{$hCoverageList})))
|
||||||
|
{
|
||||||
|
if (@{$hCoverageList->{$strCodeModule}} > 0)
|
||||||
|
{
|
||||||
|
my $iCoverageTotal = 0;
|
||||||
|
|
||||||
|
foreach my $hTest (@{$hCoverageList->{$strCodeModule}})
|
||||||
|
{
|
||||||
|
if (!defined($hModuleTest->{$hTest->{strModule}}{$hTest->{strTest}}))
|
||||||
|
{
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
$iCoverageTotal++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (@{$hCoverageList->{$strCodeModule}} == $iCoverageTotal)
|
||||||
|
{
|
||||||
|
$hCoverageActual->{testRunName($strCodeModule, false)} = $hCoverageType->{$strCodeModule};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keys(%{$hCoverageActual}) == 0)
|
||||||
|
{
|
||||||
|
&log(INFO, 'no code modules had all tests run required for coverage');
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate C coverage report
|
||||||
|
#---------------------------------------------------------------------------------------------------------------------------
|
||||||
|
&log(INFO, 'writing C coverage report');
|
||||||
|
|
||||||
|
my $strLCovFile = "${strWorkTmpPath}/all.lcov";
|
||||||
|
|
||||||
|
if ($oStorage->exists($strLCovFile))
|
||||||
|
{
|
||||||
|
executeTest(
|
||||||
|
"genhtml ${strLCovFile} --config-file=${strTestResultCoveragePath}/raw/lcov.conf" .
|
||||||
|
" --prefix=${strWorkTmpPath}/repo" .
|
||||||
|
" --output-directory=${strTestResultCoveragePath}/lcov");
|
||||||
|
|
||||||
|
foreach my $strCodeModule (sort(keys(%{$hCoverageActual})))
|
||||||
|
{
|
||||||
|
my $strCoverageFile = $strCodeModule;
|
||||||
|
$strCoverageFile =~ s/^module/test/mg;
|
||||||
|
$strCoverageFile = "${strTestResultCoveragePath}/raw/${strCoverageFile}.lcov";
|
||||||
|
|
||||||
|
my $strCoverage = $oStorage->get($oStorage->openRead($strCoverageFile, {bIgnoreMissing => true}));
|
||||||
|
|
||||||
|
if (defined($strCoverage) && defined($$strCoverage))
|
||||||
|
{
|
||||||
|
my $iTotalLines = (split(':', ($$strCoverage =~ m/^LF\:.*$/mg)[0]))[1] + 0;
|
||||||
|
my $iCoveredLines = (split(':', ($$strCoverage =~ m/^LH\:.*$/mg)[0]))[1] + 0;
|
||||||
|
|
||||||
|
my $iTotalBranches = 0;
|
||||||
|
my $iCoveredBranches = 0;
|
||||||
|
|
||||||
|
if ($$strCoverage =~ /^BRF\:/mg && $$strCoverage =~ /^BRH\:/mg)
|
||||||
|
{
|
||||||
|
# If this isn't here the statements below fail -- huh?
|
||||||
|
my @match = $$strCoverage =~ m/^BRF\:.*$/mg;
|
||||||
|
|
||||||
|
$iTotalBranches = (split(':', ($$strCoverage =~ m/^BRF\:.*$/mg)[0]))[1] + 0;
|
||||||
|
$iCoveredBranches = (split(':', ($$strCoverage =~ m/^BRH\:.*$/mg)[0]))[1] + 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate detail if there is missing coverage
|
||||||
|
my $strDetail = undef;
|
||||||
|
|
||||||
|
if ($iCoveredLines != $iTotalLines)
|
||||||
|
{
|
||||||
|
$strDetail .= "$iCoveredLines/$iTotalLines lines";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($iTotalBranches != $iCoveredBranches)
|
||||||
|
{
|
||||||
|
$strDetail .= (defined($strDetail) ? ', ' : '') . "$iCoveredBranches/$iTotalBranches branches";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defined($strDetail))
|
||||||
|
{
|
||||||
|
&log(ERROR, "c module ${strCodeModule} is not fully covered ($strDetail)");
|
||||||
|
$result++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
coverageGenerate(
|
||||||
|
$oStorage, "${strWorkTmpPath}/repo", "${strTestResultCoveragePath}/raw", "${strTestResultCoveragePath}/coverage.html");
|
||||||
|
|
||||||
|
if ($bCoverageSummary)
|
||||||
|
{
|
||||||
|
&log(INFO, 'writing C coverage summary report');
|
||||||
|
|
||||||
|
coverageDocSummaryGenerate(
|
||||||
|
$oStorage, "${strTestResultCoveragePath}/raw", "${strTestResultSummaryPath}/metric-coverage-report.auto.xml");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
executeTest("rm -rf ${strTestResultCoveragePath}/test/tesult/coverage");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
push @EXPORT, qw(coverageValidateAndGenerate);
|
||||||
|
|
||||||
####################################################################################################################################
|
####################################################################################################################################
|
||||||
# Generate a C coverage report
|
# Generate a C coverage report
|
||||||
####################################################################################################################################
|
####################################################################################################################################
|
||||||
|
|||||||
@@ -610,134 +610,10 @@ sub end
|
|||||||
# If C code generate coverage info
|
# If C code generate coverage info
|
||||||
if ($iExitStatus == 0 && $self->{oTest}->{&TEST_C} && vmCoverageC($self->{oTest}->{&TEST_VM}) && $self->{bCoverageUnit})
|
if ($iExitStatus == 0 && $self->{oTest}->{&TEST_C} && vmCoverageC($self->{oTest}->{&TEST_VM}) && $self->{bCoverageUnit})
|
||||||
{
|
{
|
||||||
# Generate a list of files to cover
|
coverageExtract(
|
||||||
my $hTestCoverage =
|
$self->{oStorageTest}, $self->{oTest}->{&TEST_MODULE}, $self->{oTest}->{&TEST_NAME}, $self->{bCoverageSummary},
|
||||||
(testDefModuleTest($self->{oTest}->{&TEST_MODULE}, $self->{oTest}->{&TEST_NAME}))->{&TESTDEF_COVERAGE};
|
$self->{oTest}->{&TEST_VM} eq VM_NONE ? undef : $strImage, $self->{strTestPath}, "$self->{strTestPath}/temp",
|
||||||
|
$self->{strGCovPath}, $self->{strBackRestBase} . '/test/result');
|
||||||
my @stryCoveredModule;
|
|
||||||
|
|
||||||
foreach my $strModule (sort(keys(%{$hTestCoverage})))
|
|
||||||
{
|
|
||||||
push (@stryCoveredModule, $strModule);
|
|
||||||
}
|
|
||||||
|
|
||||||
push(
|
|
||||||
@stryCoveredModule,
|
|
||||||
"module/$self->{oTest}->{&TEST_MODULE}/" . testRunName($self->{oTest}->{&TEST_NAME}, false) . 'Test');
|
|
||||||
|
|
||||||
# Generate coverage reports for the modules
|
|
||||||
my $strLCovConf = $self->{strBackRestBase} . '/test/result/coverage/raw/lcov.conf';
|
|
||||||
coverageLCovConfigGenerate($self->{oStorageTest}, $strLCovConf, $self->{bCoverageSummary});
|
|
||||||
|
|
||||||
my $strLCovExeBase = "lcov --config-file=${strLCovConf}";
|
|
||||||
my $strLCovOut = $self->{strGCovPath} . '/test.lcov';
|
|
||||||
my $strLCovOutTmp = $self->{strGCovPath} . '/test.tmp.lcov';
|
|
||||||
|
|
||||||
executeTest(
|
|
||||||
($self->{oTest}->{&TEST_VM} ne VM_NONE ? 'docker exec -i -u ' . TEST_USER . " ${strImage} " : '') .
|
|
||||||
"${strLCovExeBase} --capture --directory=$self->{strGCovPath} --o=${strLCovOut}");
|
|
||||||
|
|
||||||
# Generate coverage report for each module
|
|
||||||
foreach my $strModule (@stryCoveredModule)
|
|
||||||
{
|
|
||||||
my $strModuleName = testRunName($strModule, false);
|
|
||||||
my $strModuleOutName = $strModuleName;
|
|
||||||
my $bTest = false;
|
|
||||||
|
|
||||||
if ($strModuleOutName =~ /^module/mg)
|
|
||||||
{
|
|
||||||
$strModuleOutName =~ s/^module/test/mg;
|
|
||||||
$bTest = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Disable branch coverage for test files
|
|
||||||
my $strLCovExe = $strLCovExeBase;
|
|
||||||
|
|
||||||
if ($bTest)
|
|
||||||
{
|
|
||||||
$strLCovExe .= ' --rc lcov_branch_coverage=0';
|
|
||||||
}
|
|
||||||
|
|
||||||
# Generate lcov reports
|
|
||||||
my $strModulePath =
|
|
||||||
$self->{strTestPath} . "/repo/" .
|
|
||||||
(${strModuleOutName} =~ /^test\// ?
|
|
||||||
'test/src/module/' . substr(${strModuleOutName}, 5) : "src/${strModuleOutName}");
|
|
||||||
my $strLCovFile = $self->{strBackRestBase} . "/test/result/coverage/raw/${strModuleOutName}.lcov";
|
|
||||||
my $strLCovTotal = $self->{strTestPath} . "/temp/all.lcov";
|
|
||||||
|
|
||||||
executeTest(
|
|
||||||
"${strLCovExe} --extract=${strLCovOut} */${strModuleName}.c --o=${strLCovOutTmp}");
|
|
||||||
|
|
||||||
# Combine with prior run if there was one
|
|
||||||
if ($self->{oStorageTest}->exists($strLCovFile))
|
|
||||||
{
|
|
||||||
my $strCoverage = ${$self->{oStorageTest}->get($strLCovOutTmp)};
|
|
||||||
$strCoverage =~ s/^SF\:.*$/SF:$strModulePath\.c/mg;
|
|
||||||
$self->{oStorageTest}->put($strLCovOutTmp, $strCoverage);
|
|
||||||
|
|
||||||
executeTest(
|
|
||||||
"${strLCovExe} --add-tracefile=${strLCovOutTmp} --add-tracefile=${strLCovFile} --o=${strLCovOutTmp}");
|
|
||||||
}
|
|
||||||
|
|
||||||
# Update source file
|
|
||||||
my $strCoverage = ${$self->{oStorageTest}->get($strLCovOutTmp)};
|
|
||||||
|
|
||||||
if (defined($strCoverage))
|
|
||||||
{
|
|
||||||
if (!$bTest && $hTestCoverage->{$strModule} eq TESTDEF_COVERAGE_NOCODE)
|
|
||||||
{
|
|
||||||
confess &log(ERROR, "module '${strModule}' is marked 'no code' but has code");
|
|
||||||
}
|
|
||||||
|
|
||||||
# Get coverage info
|
|
||||||
my $iTotalLines = (split(':', ($strCoverage =~ m/^LF:.*$/mg)[0]))[1] + 0;
|
|
||||||
my $iCoveredLines = (split(':', ($strCoverage =~ m/^LH:.*$/mg)[0]))[1] + 0;
|
|
||||||
|
|
||||||
my $iTotalBranches = 0;
|
|
||||||
my $iCoveredBranches = 0;
|
|
||||||
|
|
||||||
if ($strCoverage =~ /^BRF\:/mg && $strCoverage =~ /^BRH\:/mg)
|
|
||||||
{
|
|
||||||
# If this isn't here the statements below fail -- huh?
|
|
||||||
my @match = $strCoverage =~ m/^BRF\:.*$/mg;
|
|
||||||
|
|
||||||
$iTotalBranches = (split(':', ($strCoverage =~ m/^BRF:.*$/mg)[0]))[1] + 0;
|
|
||||||
$iCoveredBranches = (split(':', ($strCoverage =~ m/^BRH:.*$/mg)[0]))[1] + 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Report coverage if this is not a test or if the test does not have complete coverage
|
|
||||||
if (!$bTest || $iTotalLines != $iCoveredLines || $iTotalBranches != $iCoveredBranches)
|
|
||||||
{
|
|
||||||
# Fix source file name
|
|
||||||
$strCoverage =~ s/^SF\:.*$/SF:$strModulePath\.c/mg;
|
|
||||||
|
|
||||||
$self->{oStorageTest}->put(
|
|
||||||
$self->{oStorageTest}->openWrite($strLCovFile, {bPathCreate => true}), $strCoverage);
|
|
||||||
|
|
||||||
if ($self->{oStorageTest}->exists($strLCovTotal))
|
|
||||||
{
|
|
||||||
executeTest(
|
|
||||||
"${strLCovExe} --add-tracefile=${strLCovFile} --add-tracefile=${strLCovTotal} --o=${strLCovTotal}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$self->{oStorageTest}->copy($strLCovFile, $strLCovTotal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$self->{oStorageTest}->remove($strLCovFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ($hTestCoverage->{$strModule} ne TESTDEF_COVERAGE_NOCODE)
|
|
||||||
{
|
|
||||||
confess &log(ERROR, "module '${strModule}' is marked 'code' but has no code");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Record elapsed time
|
# Record elapsed time
|
||||||
|
|||||||
+3
-141
@@ -1117,147 +1117,9 @@ eval
|
|||||||
|
|
||||||
if (vmCoverageC($strVm) && !$bNoCoverage && !$bDryRun && $iTestFail == 0)
|
if (vmCoverageC($strVm) && !$bNoCoverage && !$bDryRun && $iTestFail == 0)
|
||||||
{
|
{
|
||||||
# Determine which modules were covered (only check coverage if all tests were successful)
|
$iUncoveredCodeModuleTotal = coverageValidateAndGenerate(
|
||||||
#-----------------------------------------------------------------------------------------------------------------------
|
$oyTestRun, $oStorageBackRest, $bCoverageSummary, "${strTestPath}/temp", "${strBackRestBase}/test/result",
|
||||||
my $hModuleTest; # Everything that was run
|
"${strBackRestBase}/doc/xml/auto");
|
||||||
|
|
||||||
# Build a hash of all modules, tests, and runs that were executed
|
|
||||||
foreach my $hTestRun (@{$oyTestRun})
|
|
||||||
{
|
|
||||||
# Get coverage for the module
|
|
||||||
my $strModule = $hTestRun->{&TEST_MODULE};
|
|
||||||
my $hModule = testDefModule($strModule);
|
|
||||||
|
|
||||||
# Get coverage for the test
|
|
||||||
my $strTest = $hTestRun->{&TEST_NAME};
|
|
||||||
my $hTest = testDefModuleTest($strModule, $strTest);
|
|
||||||
|
|
||||||
# If no tests are listed it means all of them were run
|
|
||||||
if (@{$hTestRun->{&TEST_RUN}} == 0)
|
|
||||||
{
|
|
||||||
$hModuleTest->{$strModule}{$strTest} = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Now compare against code modules that should have full coverage
|
|
||||||
my $hCoverageList = testDefCoverageList();
|
|
||||||
my $hCoverageType = testDefCoverageType();
|
|
||||||
my $hCoverageActual;
|
|
||||||
|
|
||||||
foreach my $strCodeModule (sort(keys(%{$hCoverageList})))
|
|
||||||
{
|
|
||||||
if (@{$hCoverageList->{$strCodeModule}} > 0)
|
|
||||||
{
|
|
||||||
my $iCoverageTotal = 0;
|
|
||||||
|
|
||||||
foreach my $hTest (@{$hCoverageList->{$strCodeModule}})
|
|
||||||
{
|
|
||||||
if (!defined($hModuleTest->{$hTest->{strModule}}{$hTest->{strTest}}))
|
|
||||||
{
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
$iCoverageTotal++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (@{$hCoverageList->{$strCodeModule}} == $iCoverageTotal)
|
|
||||||
{
|
|
||||||
$hCoverageActual->{testRunName($strCodeModule, false)} = $hCoverageType->{$strCodeModule};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keys(%{$hCoverageActual}) == 0)
|
|
||||||
{
|
|
||||||
&log(INFO, 'no code modules had all tests run required for coverage');
|
|
||||||
}
|
|
||||||
|
|
||||||
# Generate C coverage report
|
|
||||||
#---------------------------------------------------------------------------------------------------------------------------
|
|
||||||
if (vmCoverageC($strVm))
|
|
||||||
{
|
|
||||||
&log(INFO, 'writing C coverage report');
|
|
||||||
|
|
||||||
my $strLCovFile = "${strTestPath}/temp/all.lcov";
|
|
||||||
|
|
||||||
if ($oStorageBackRest->exists($strLCovFile))
|
|
||||||
{
|
|
||||||
executeTest(
|
|
||||||
"genhtml ${strLCovFile} --config-file=${strBackRestBase}/test/result/coverage/raw/lcov.conf" .
|
|
||||||
" --prefix=${strTestPath}/repo" .
|
|
||||||
" --output-directory=${strBackRestBase}/test/result/coverage/lcov");
|
|
||||||
|
|
||||||
foreach my $strCodeModule (sort(keys(%{$hCoverageActual})))
|
|
||||||
{
|
|
||||||
# If the first char of the module is upper case then it's a Perl module
|
|
||||||
if (substr($strCodeModule, 0, 1) eq uc(substr($strCodeModule, 0, 1)))
|
|
||||||
{
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $strCoverageFile = $strCodeModule;
|
|
||||||
$strCoverageFile =~ s/^module/test/mg;
|
|
||||||
$strCoverageFile = "${strBackRestBase}/test/result/coverage/raw/${strCoverageFile}.lcov";
|
|
||||||
|
|
||||||
my $strCoverage = $oStorageBackRest->get(
|
|
||||||
$oStorageBackRest->openRead($strCoverageFile, {bIgnoreMissing => true}));
|
|
||||||
|
|
||||||
if (defined($strCoverage) && defined($$strCoverage))
|
|
||||||
{
|
|
||||||
my $iTotalLines = (split(':', ($$strCoverage =~ m/^LF\:.*$/mg)[0]))[1] + 0;
|
|
||||||
my $iCoveredLines = (split(':', ($$strCoverage =~ m/^LH\:.*$/mg)[0]))[1] + 0;
|
|
||||||
|
|
||||||
my $iTotalBranches = 0;
|
|
||||||
my $iCoveredBranches = 0;
|
|
||||||
|
|
||||||
if ($$strCoverage =~ /^BRF\:/mg && $$strCoverage =~ /^BRH\:/mg)
|
|
||||||
{
|
|
||||||
# If this isn't here the statements below fail -- huh?
|
|
||||||
my @match = $$strCoverage =~ m/^BRF\:.*$/mg;
|
|
||||||
|
|
||||||
$iTotalBranches = (split(':', ($$strCoverage =~ m/^BRF\:.*$/mg)[0]))[1] + 0;
|
|
||||||
$iCoveredBranches = (split(':', ($$strCoverage =~ m/^BRH\:.*$/mg)[0]))[1] + 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Generate detail if there is missing coverage
|
|
||||||
my $strDetail = undef;
|
|
||||||
|
|
||||||
if ($iCoveredLines != $iTotalLines)
|
|
||||||
{
|
|
||||||
$strDetail .= "$iCoveredLines/$iTotalLines lines";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($iTotalBranches != $iCoveredBranches)
|
|
||||||
{
|
|
||||||
$strDetail .= (defined($strDetail) ? ', ' : '') . "$iCoveredBranches/$iTotalBranches branches";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defined($strDetail))
|
|
||||||
{
|
|
||||||
&log(ERROR, "c module ${strCodeModule} is not fully covered ($strDetail)");
|
|
||||||
$iUncoveredCodeModuleTotal++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
coverageGenerate(
|
|
||||||
$oStorageBackRest, "${strTestPath}/repo", "${strBackRestBase}/test/result/coverage/raw",
|
|
||||||
"${strBackRestBase}/test/result/coverage/coverage.html");
|
|
||||||
|
|
||||||
if ($bCoverageSummary)
|
|
||||||
{
|
|
||||||
&log(INFO, 'writing C coverage summary report');
|
|
||||||
|
|
||||||
coverageDocSummaryGenerate(
|
|
||||||
$oStorageBackRest, "${strBackRestBase}/test/result/coverage/raw",
|
|
||||||
"${strBackRestBase}/doc/xml/auto/metric-coverage-report.auto.xml");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
executeTest("rm -rf ${strBackRestBase}/test/tesult/coverage");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Print test info and exit
|
# Print test info and exit
|
||||||
|
|||||||
Reference in New Issue
Block a user