A different set of tests are run depending on whether a VM's mission
is test=test (the default) or test=module. Being unable to distinguish
these two cases prevents checking that the right set of test units is
being run in many cases.
So add support for the wine:build, wine:test, wine:module categories to
allow providing specific checks for the test=build/test/module cases
respectively.
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
testbot/tests/TestWTBS | 184 +++++++++++++++++++++++++++++------------
1 file changed, 131 insertions(+), 53 deletions(-)
diff --git a/testbot/tests/TestWTBS b/testbot/tests/TestWTBS
index bc4e0d9ba..f6ca54e84 100755
--- a/testbot/tests/TestWTBS
+++ b/testbot/tests/TestWTBS
@@ -48,6 +48,7 @@ use WineTestBot::Config; # For $PatchesMailingList
use WineTestBot::Jobs;
use WineTestBot::Log;
use WineTestBot::LogUtils;
+use WineTestBot::Missions;
use WineTestBot::Patches;
use WineTestBot::VMs;
@@ -190,13 +191,15 @@ Property names are of the form 'category.name' where the category is one of:
- build for checks to perform on the build task.
- win32, win64 for checks to perform on the Windows 32- or 64-bit test results
respectively.
-- win for the checks to perform on both the 32- and 64-bit test results; that
- is equivalent to duplicating the directive for the win32 and win64
- categories.
-- wine for the checks to perform on the Wine test results.
+- win for the checks to perform on both the 32- and 64-bit test results. This
+ is equivalent to duplicating the directive for win32 and win64.
+- wine:build, wine:test, wine:module for checks to perform on test results of
+ missions with test=build, test=test and test=module respectively.
+- wine for the checks to perform on the Wine test results. This is equivalent
+ to duplicating the directive for the wine:build, wine:test and wine:module.
- tests for checks to perform on all test results, that is equivalent to
- duplicating the directive for the win32, win64 and wine categories (but not
- build since it does not run the tests).
+ duplicating the directive for the win and wine categories (but not build
+ since it does not run the tests).
A corollary is that any property which is documented as being valid for a
category can also be specified for any of its subcategories. So for instance if
@@ -208,8 +211,9 @@ sub DumpTestInfo($)
{
my ($TestInfo) = @_;
- foreach my $Category ("webpatch", "patch", "job", "tasks", "tests", "win",
- "build", "win32", "win64", "wine")
+ foreach my $Category ("webpatch", "patch", "job", "tasks", "tests", "build",
+ "win", "win32", "win64",
+ "wine", "wine:build", "wine:test", "wine:module")
{
WineTestBot::LogUtils::_WriteLogErrorsToFh(*STDERR, $TestInfo->{$Category});
WineTestBot::LogUtils::_DumpErrors($Category, $TestInfo->{$Category});
@@ -293,14 +297,15 @@ sub LoadTestInfo($)
# Split up the information to jobs, tasks, etc.
my $TestInfo = {
webpatch => {}, patch => {}, job => {},
- tasks => {}, tests => {}, win => {},
- build => {}, win32 => {}, win64 => {}, wine => {},
+ tasks => {}, tests => {}, build => {},
+ win => {}, win32 => {}, win64 => {},
+ wine => {}, "wine:build" => {}, "wine:test" => {}, "wine:module" => {},
};
my $HasTestInfo;
foreach my $Entry (keys %{$RawInfo})
{
my $Field = lcfirst($Entry);
- if ($Field =~ s/^(webpatch|patch|job|tasks|tests|win|build|win32|win64|wine)\.//)
+ if ($Field =~ s/^(webpatch|patch|job|tasks|tests|build|win|win32|win64|wine|wine:build|wine:test|wine:module)\.//)
{
my $TaskType = $1;
$TestInfo->{$TaskType}->{$Field} = $RawInfo->{$Entry};
@@ -314,7 +319,7 @@ sub LoadTestInfo($)
foreach my $RawGroupName (@{$RawInfo->{ErrGroupNames}})
{
my $GroupName = lcfirst($RawGroupName);
- if ($GroupName =~ s/^(tasks|build|tests|win|win32|win64|wine)\.(report|log|testbot)\.//)
+ if ($GroupName =~ s/^(tasks|tests|build|win|win32|win64|wine|wine:build|wine:test|wine:module)\.(report|log|testbot)\.//)
{
my $ErrInfo = ($TestInfo->{$1}->{"$2.errors"} ||= {});
push @{$ErrInfo->{ErrGroupNames}}, $GroupName;
@@ -338,11 +343,16 @@ sub LoadTestInfo($)
SetDefault($TestInfo, "tasks", "Status", "completed");
SetDefault($TestInfo, "tasks", "HasTask", 1);
}
+ if (defined $TestInfo->{"wine:build"}->{TestUnits})
+ {
+ fail("wine:build.TestUnits should not be set");
+ }
# Then propagate the defaults
foreach my $Pair (["tasks", ["build", "tests"]],
["tests", ["win", "wine"]],
- ["win", ["win32", "win64"]])
+ ["win", ["win32", "win64"]],
+ ["wine", ["wine:test", "wine:module"]])
{
my ($Src, $TaskTypes) = @$Pair;
foreach my $Field (keys %{$TestInfo->{$Src}})
@@ -368,41 +378,51 @@ sub LoadTestInfo($)
}
}
}
+ # Reset the inherited wine:build.TestUnits since it makes no sense
+ delete $TestInfo->{"wine:build"}->{TestUnits};
# Automatically check the Task: lines in simple cases
- # Make sure no test is run for build tasks
- my $GrepV = ($TestInfo->{build}->{"report.GrepV"} ||= []);
- push @$GrepV, '.';
- $GrepV = ($TestInfo->{build}->{"log.GrepV"} ||= []);
- push @$GrepV, '^Task: tests$';
- if (($TestInfo->{build}->{Status} || "") =~ /^bad(?:build|patch)$/ or
- $TestInfo->{build}->{HasTimeout})
- {
- push @$GrepV, '^Task: ok$';
- }
- else
+ foreach my $Build ("build", "wine:build")
{
- my $Grep = ($TestInfo->{build}->{"log.Grep"} ||= []);
- push @$Grep, '^Task: ok$';
+ # Make sure no test is run for build tasks
+ my $GrepV = ($TestInfo->{$Build}->{"report.GrepV"} ||= []);
+ push @$GrepV, '.';
+ $GrepV = ($TestInfo->{$Build}->{"log.GrepV"} ||= []);
+ push @$GrepV, '^Task: tests$';
+
+ if (($TestInfo->{$Build}->{Status} || "") =~ /^bad(?:build|patch)$/ or
+ $TestInfo->{$Build}->{HasTimeout})
+ {
+ push @$GrepV, '^Task: ok$';
+ }
+ else
+ {
+ my $Grep = ($TestInfo->{$Build}->{"log.Grep"} ||= []);
+ push @$Grep, '^Task: ok$';
+ }
}
- # Note: Depending on where the timeout occurs, the wine task log may or
- # may not have a 'Task: ok' line.
- if (($TestInfo->{wine}->{Status} || "") eq "completed" and
- !$TestInfo->{wine}->{HasTimeout})
+ foreach my $Test ("test", "module")
{
- my $Grep = ($TestInfo->{wine}->{"log.Grep"} ||= []);
- if (CheckValue($TestInfo->{wine}->{TestUnits}))
+ # Note: Depending on where the timeout occurs, the wine task log may or
+ # may not have a 'Task: ok' line.
+ if (($TestInfo->{"wine:$Test"}->{Status} || "") eq "completed" and
+ !$TestInfo->{"wine:$Test"}->{HasTimeout})
{
- push @$Grep, '^Task: tests$';
+ my $Grep = ($TestInfo->{"wine:$Test"}->{"log.Grep"} ||= []);
+ if (CheckValue($TestInfo->{"wine:$Test"}->{TestUnits}))
+ {
+ push @$Grep, '^Task: tests$';
+ }
+ push @$Grep, '^Task: ok$';
}
- push @$Grep, '^Task: ok$';
}
# Validate and fix the Grep* fields
foreach my $GrepType ("Grep", "GrepV")
{
- foreach my $TaskType ("tasks", "tests", "build", "win", "win32", "win64", "wine")
+ foreach my $TaskType ("tasks", "tests", "build", "win", "win32", "win64",
+ "wine", "wine:build", "wine:test", "wine:module")
{
foreach my $LogType ("report", "log", "testbot")
{
@@ -426,15 +446,19 @@ sub LoadTestInfo($)
CheckValue($TestInfo->{job}->{Status}) and
!SkipCheck($TestInfo->{win32}->{TestFailures}) and
!SkipCheck($TestInfo->{win64}->{TestFailures}) and
- !SkipCheck($TestInfo->{wine}->{TestFailures}))
+ !SkipCheck($TestInfo->{"wine:test"}->{TestFailures}) and
+ !SkipCheck($TestInfo->{"wine:module"}->{TestFailures}))
{
my $Status = ($TestInfo->{job}->{Status} ne 'completed' or
$TestInfo->{win32}->{TestFailures} or
$TestInfo->{win64}->{TestFailures} or
- $TestInfo->{wine}->{TestFailures} or
+ $TestInfo->{"wine:test"}->{TestFailures} or
+ $TestInfo->{"wine:module"}->{TestFailures} or
$TestInfo->{win32}->{HasTimeout} or
$TestInfo->{win64}->{HasTimeout} or
- $TestInfo->{wine}->{HasTimeout}) ? "Failed" : "OK";
+ $TestInfo->{"wine:build"}->{HasTimeout} or
+ $TestInfo->{"wine:test"}->{HasTimeout} or
+ $TestInfo->{"wine:module"}->{HasTimeout}) ? "Failed" : "OK";
SetDefault($TestInfo, "webpatch", "Status", $Status);
}
@@ -828,9 +852,30 @@ sub CheckTask($$$$)
$TestUnits->{$TaskType}->{"*skipped*"} = 1;
}
+ # Assume the VM's Missions field has not changed since the tests were run
+ my ($ErrMessage, $Missions) = ParseMissionStatement($Task->Missions);
+ if (@$Missions != 1)
+ {
+ fail(TaskKeyStr($Task) ." has an invalid missions field: ". $Task->Missions);
+ return;
+ }
+
+ my %ReportTypes;
+ if ($TaskType =~ /^win/)
+ {
+ foreach my $Mission (@{$Missions->[0]->{Missions}})
+ {
+ my $ReportName = GetMissionBaseName($Mission) .".report";
+ my $MissionType = $TaskType;
+ $MissionType .= ":". ($Mission->{test} || "test") if ($TaskType eq "wine");
+ $ReportTypes{$ReportName} = $MissionType;
+ }
+ }
+
my $CheckTimeouts = ($Task->Status eq "completed" and
CheckValue($TaskInfo->{HasTimeout}));
+ my $ExpectedFailures;
my ($ReportCount, $TimeoutCount, $NewFailures) = (0, 0, 0);
foreach my $LogName (@{GetLogFileNames($Task->GetDir())})
{
@@ -838,15 +883,33 @@ sub CheckTask($$$$)
my $LogInfo = LoadLogErrors($LogPath);
$NewFailures += $LogInfo->{NewCount} || 0;
+ # Get the mission-specific "wine:xxx" report directives
+ my $MissionType = $ReportTypes{$LogName} || $TaskType;
+ my $MissionInfo = $TestInfo->{$MissionType};
my $LogType = "log";
if ($LogName =~ /\.report$/)
{
- $ReportCount++;
$LogType = "report";
+ $ReportCount++;
+
+ ok($ReportTypes{$LogName}, "Check that $LogName is expected");
+
if ($TaskType eq "wine")
{
my $ReportTestUnits = GetReportTestUnits($LogPath);
- map { $TestUnits->{wine}->{$_} = 1 } (keys %$ReportTestUnits);
+ map { $TestUnits->{$MissionType}->{$_} = 1 } (keys %$ReportTestUnits);
+ }
+
+ if (CheckValue($MissionInfo->{TestFailures}))
+ {
+ ok(($LogInfo->{ErrCount} || 0) <= $MissionInfo->{TestFailures},
+ "Check Failures of $LogName in task ". TaskKeyStr($Task))
+ or diag("report error count = ", ($LogInfo->{ErrCount} || 0), ", expected at most $MissionInfo->{TestFailures}");
+ $ExpectedFailures += $MissionInfo->{TestFailures};
+ }
+ else
+ {
+ $ExpectedFailures = undef;
}
}
elsif ($LogName =~ /^testbot\./)
@@ -854,24 +917,35 @@ sub CheckTask($$$$)
$LogType = "testbot";
}
- if ($TaskInfo->{"$LogType.errors"} or $CheckTimeouts)
+ if ($MissionInfo->{"$LogType.errors"} or $CheckTimeouts)
{
- my $HasTimeout = CheckLogErrors($LogInfo, $TaskInfo->{"$LogType.errors"},
+ my $HasTimeout = CheckLogErrors($LogInfo, $MissionInfo->{"$LogType.errors"},
TaskKeyStr($Task) ."/$LogName",
- $TaskInfo->{HasTimeout});
+ $MissionInfo->{HasTimeout});
$TimeoutCount++ if ($HasTimeout);
}
- GrepTaskLog($Task, $LogName, $TaskInfo, "$LogType.");
+ GrepTaskLog($Task, $LogName, $MissionInfo, "$LogType.");
}
if ($CheckTimeouts)
{
ok($TimeoutCount >= $ReportCount, "Expecting 1+ timeout per report: $TimeoutCount timeouts, $ReportCount reports");
}
- if ($Task->Status eq "completed" and CheckValue($TaskInfo->{TestFailures}))
+ if ($Task->Status eq "completed")
{
- # Scale the expected TestFailures count with the number of times the test
- # was run, i.e. $ReportCount, or take it as is if no report is available.
- is($Task->TestFailures, $TaskInfo->{TestFailures} * ($ReportCount || 1), "Check Failures of task ". TaskKeyStr($Task));
+ if (defined $ExpectedFailures)
+ {
+ is($Task->TestFailures, $ExpectedFailures, "Check Failures of task ". TaskKeyStr($Task));
+ }
+ elsif (CheckValue($TaskInfo->{TestFailures}) and !$ReportCount)
+ {
+ # Scale the expected TestFailures count with the number of times the test
+ # was run, i.e. $ReportCount, or take it as is if no report is available.
+ is($Task->TestFailures, $TaskInfo->{TestFailures}, "Check Failures of task ". TaskKeyStr($Task));
+ }
+ # else there are reports for which we cannot check the TestFailures count.
+ # In particular this can happen if the test failure count can be checked
+ # for test=test but not for test=module. Then whether TestFailures can be
+ # checked or not depends on the missions mix.
}
return $NewFailures;
}
@@ -973,7 +1047,7 @@ sub CheckJobTree($;$)
$CheckedJobs{$JobId} = 1;
my ($HasTask, $HasNewFailures);
- my $TestUnits = { wine => {} };
+ my $TestUnits = {};
my $Email = $Emails{$JobId};
my %FailedVMs;
@@ -1059,12 +1133,16 @@ sub CheckJobTree($;$)
}
next if ($TestUnits->{$Type}->{"*skipped*"});
- if (CheckValue($TypeInfo->{TestUnits}))
+ my @MissionTypes = $Type eq "wine" ? ("wine:test", "wine:module") : ($Type);
+ foreach my $MissionType (@MissionTypes)
{
- foreach my $TestUnit (split / +/, $TypeInfo->{TestUnits})
+ my $MissionInfo = $TestInfo->{$MissionType};
+ next if (!CheckValue($MissionInfo->{TestUnits}));
+
+ foreach my $TestUnit (split / +/, $MissionInfo->{TestUnits})
{
- ok($TestUnits->{$Type}->{$TestUnit}, "Check that $TestUnit was tested by $Type VMs for job $JobId")
- or diag("TestUnits=", join(" ", sort keys %{$TestUnits->{$Type}}));
+ ok($TestUnits->{$MissionType}->{$TestUnit}, "Check that $TestUnit was tested by $MissionType VMs for job $JobId")
+ or diag("TestUnits=", join(" ", sort keys %{$TestUnits->{$MissionType}}));
}
}
}
--
2.20.1