Tests: restructure to more closely mirror the sources
t/ had lots of directories and files mirroring src/lib/Hydra. This moves those files under t/Hydra
This commit is contained in:
63
t/Hydra/Plugin/RunCommand/basic.t
Normal file
63
t/Hydra/Plugin/RunCommand/basic.t
Normal file
@ -0,0 +1,63 @@
|
||||
use feature 'unicode_strings';
|
||||
use strict;
|
||||
use warnings;
|
||||
use JSON::MaybeXS;
|
||||
use Setup;
|
||||
|
||||
my %ctx = test_init(
|
||||
hydra_config => q|
|
||||
<runcommand>
|
||||
command = cp "$HYDRA_JSON" "$HYDRA_DATA/joboutput.json"
|
||||
</runcommand>
|
||||
|);
|
||||
|
||||
require Hydra::Schema;
|
||||
require Hydra::Model::DB;
|
||||
|
||||
use Test2::V0;
|
||||
|
||||
my $db = Hydra::Model::DB->new;
|
||||
hydra_setup($db);
|
||||
|
||||
my $project = $db->resultset('Projects')->create({name => "tests", displayname => "", owner => "root"});
|
||||
|
||||
# Most basic test case, no parameters
|
||||
my $jobset = createBaseJobset("basic", "runcommand.nix", $ctx{jobsdir});
|
||||
|
||||
ok(evalSucceeds($jobset), "Evaluating jobs/runcommand.nix should exit with return code 0");
|
||||
is(nrQueuedBuildsForJobset($jobset), 1, "Evaluating jobs/runcommand.nix should result in 1 build1");
|
||||
|
||||
(my $build) = queuedBuildsForJobset($jobset);
|
||||
|
||||
is($build->job, "metrics", "The only job should be metrics");
|
||||
ok(runBuild($build), "Build should exit with return code 0");
|
||||
my $newbuild = $db->resultset('Builds')->find($build->id);
|
||||
is($newbuild->finished, 1, "Build should be finished.");
|
||||
is($newbuild->buildstatus, 0, "Build should have buildstatus 0.");
|
||||
|
||||
ok(sendNotifications(), "Notifications execute successfully.");
|
||||
|
||||
my $dat = do {
|
||||
my $filename = $ENV{'HYDRA_DATA'} . "/joboutput.json";
|
||||
open(my $json_fh, "<", $filename)
|
||||
or die("Can't open \"$filename\": $!\n");
|
||||
local $/;
|
||||
my $json = JSON::MaybeXS->new;
|
||||
$json->decode(<$json_fh>)
|
||||
};
|
||||
|
||||
subtest "Validate the file parsed and at least one field matches" => sub {
|
||||
is($dat->{build}, $newbuild->id, "The build event matches our expected ID.");
|
||||
};
|
||||
|
||||
subtest "Validate a run log was created" => sub {
|
||||
my $runlog = $build->runcommandlogs->find({});
|
||||
ok($runlog->did_succeed(), "The process did succeed.");
|
||||
is($runlog->job_matcher, "*:*:*", "An unspecified job matcher is defaulted to *:*:*");
|
||||
is($runlog->command, 'cp "$HYDRA_JSON" "$HYDRA_DATA/joboutput.json"', "The executed command is saved.");
|
||||
is($runlog->start_time, within(time() - 1, 2), "The start time is recent.");
|
||||
is($runlog->end_time, within(time() - 1, 2), "The end time is also recent.");
|
||||
is($runlog->exit_code, 0, "This command should have succeeded.");
|
||||
};
|
||||
|
||||
done_testing;
|
52
t/Hydra/Plugin/RunCommand/errno.t
Normal file
52
t/Hydra/Plugin/RunCommand/errno.t
Normal file
@ -0,0 +1,52 @@
|
||||
use feature 'unicode_strings';
|
||||
use strict;
|
||||
use warnings;
|
||||
use JSON::MaybeXS;
|
||||
use Setup;
|
||||
|
||||
my %ctx = test_init(
|
||||
hydra_config => q|
|
||||
<runcommand>
|
||||
command = invalid-command-this-does-not-exist
|
||||
</runcommand>
|
||||
|);
|
||||
|
||||
require Hydra::Schema;
|
||||
require Hydra::Model::DB;
|
||||
|
||||
use Test2::V0;
|
||||
|
||||
my $db = Hydra::Model::DB->new;
|
||||
hydra_setup($db);
|
||||
|
||||
my $project = $db->resultset('Projects')->create({name => "tests", displayname => "", owner => "root"});
|
||||
|
||||
# Most basic test case, no parameters
|
||||
my $jobset = createBaseJobset("basic", "runcommand.nix", $ctx{jobsdir});
|
||||
|
||||
ok(evalSucceeds($jobset), "Evaluating jobs/runcommand.nix should exit with return code 0");
|
||||
is(nrQueuedBuildsForJobset($jobset), 1, "Evaluating jobs/runcommand.nix should result in 1 build1");
|
||||
|
||||
(my $build) = queuedBuildsForJobset($jobset);
|
||||
|
||||
is($build->job, "metrics", "The only job should be metrics");
|
||||
ok(runBuild($build), "Build should exit with return code 0");
|
||||
my $newbuild = $db->resultset('Builds')->find($build->id);
|
||||
is($newbuild->finished, 1, "Build should be finished.");
|
||||
is($newbuild->buildstatus, 0, "Build should have buildstatus 0.");
|
||||
|
||||
ok(sendNotifications(), "Notifications execute successfully.");
|
||||
|
||||
subtest "Validate a run log was created" => sub {
|
||||
my $runlog = $build->runcommandlogs->find({});
|
||||
ok(!$runlog->did_succeed(), "The process did not succeed.");
|
||||
ok($runlog->did_fail_with_exec_error(), "The process failed to start due to an exec error.");
|
||||
is($runlog->job_matcher, "*:*:*", "An unspecified job matcher is defaulted to *:*:*");
|
||||
is($runlog->command, 'invalid-command-this-does-not-exist', "The executed command is saved.");
|
||||
is($runlog->start_time, within(time() - 1, 2), "The start time is recent.");
|
||||
is($runlog->end_time, within(time() - 1, 2), "The end time is also recent.");
|
||||
is($runlog->exit_code, undef, "This command should not have executed.");
|
||||
is($runlog->error_number, 2, "This command failed to exec.");
|
||||
};
|
||||
|
||||
done_testing;
|
133
t/Hydra/Plugin/RunCommand/json.t
Normal file
133
t/Hydra/Plugin/RunCommand/json.t
Normal file
@ -0,0 +1,133 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
use JSON::MaybeXS;
|
||||
use Setup;
|
||||
|
||||
my %ctx = test_init(
|
||||
hydra_config => q|
|
||||
<runcommand>
|
||||
command = cp "$HYDRA_JSON" "$HYDRA_DATA/joboutput.json"
|
||||
</runcommand>
|
||||
|);
|
||||
|
||||
use Test2::V0;
|
||||
use Hydra::Plugin::RunCommand;
|
||||
|
||||
require Hydra::Schema;
|
||||
require Hydra::Model::DB;
|
||||
|
||||
use Test2::V0;
|
||||
|
||||
my $db = Hydra::Model::DB->new;
|
||||
hydra_setup($db);
|
||||
|
||||
my $project = $db->resultset('Projects')->create({name => "tests", displayname => "", owner => "root"});
|
||||
|
||||
# Most basic test case, no parameters
|
||||
my $jobset = createBaseJobset("basic", "runcommand.nix", $ctx{jobsdir});
|
||||
|
||||
ok(evalSucceeds($jobset), "Evaluating jobs/runcommand.nix should exit with return code 0");
|
||||
is(nrQueuedBuildsForJobset($jobset), 1, "Evaluating jobs/runcommand.nix should result in 1 build1");
|
||||
|
||||
(my $build) = queuedBuildsForJobset($jobset);
|
||||
|
||||
is($build->job, "metrics", "The only job should be metrics");
|
||||
ok(runBuild($build), "Build should exit with return code 0");
|
||||
my $newbuild = $db->resultset('Builds')->find($build->id);
|
||||
is($newbuild->finished, 1, "Build should be finished.");
|
||||
is($newbuild->buildstatus, 0, "Build should have buildstatus 0.");
|
||||
|
||||
$build = $newbuild;
|
||||
|
||||
my $dat = Hydra::Plugin::RunCommand::makeJsonPayload("buildFinished", $build);
|
||||
|
||||
subtest "Validate the top level fields match" => sub {
|
||||
is($dat->{build}, $build->id, "The build event matches our expected ID.");
|
||||
is($dat->{buildStatus}, 0, "The build status matches.");
|
||||
is($dat->{event}, "buildFinished", "The build event matches.");
|
||||
is($dat->{finished}, JSON::MaybeXS::true, "The build finished.");
|
||||
is($dat->{project}, "tests", "The project matches.");
|
||||
is($dat->{jobset}, "basic", "The jobset matches.");
|
||||
is($dat->{job}, "metrics", "The job matches.");
|
||||
is($dat->{nixName}, "my-build-product", "The nixName matches.");
|
||||
is($dat->{system}, $build->system, "The system matches.");
|
||||
is($dat->{drvPath}, $build->drvpath, "The derivation path matches.");
|
||||
is($dat->{timestamp}, $build->timestamp, "The result has a timestamp field.");
|
||||
is($dat->{startTime}, $build->starttime, "The result has a startTime field.");
|
||||
is($dat->{stopTime}, $build->stoptime, "The result has a stopTime field.");
|
||||
is($dat->{homepage}, "https://github.com/NixOS/hydra", "The homepage is passed.");
|
||||
is($dat->{description}, "An example meta property.", "The description is passed.");
|
||||
is($dat->{license}, "GPL", "The license is passed.");
|
||||
};
|
||||
|
||||
|
||||
subtest "Validate the outputs match" => sub {
|
||||
is(scalar(@{$dat->{outputs}}), 2, "There are exactly two outputs");
|
||||
|
||||
subtest "output: out" => sub {
|
||||
my ($output) = grep { $_->{name} eq "out" } @{$dat->{outputs}};
|
||||
my $expectedoutput = $build->buildoutputs->find({name => "out"});
|
||||
|
||||
is($output->{name}, "out", "Output is named corrrectly");
|
||||
is($output->{path}, $expectedoutput->path, "The output path matches the database's path.");
|
||||
};
|
||||
|
||||
subtest "output: bin" => sub {
|
||||
my ($output) = grep { $_->{name} eq "bin" } @{$dat->{outputs}};
|
||||
my $expectedoutput = $build->buildoutputs->find({name => "bin"});
|
||||
|
||||
is($output->{name}, "bin", "Output is named corrrectly");
|
||||
is($output->{path}, $expectedoutput->path, "The output path matches the database's path.");
|
||||
};
|
||||
};
|
||||
|
||||
subtest "Validate the metrics match" => sub {
|
||||
is(scalar(@{$dat->{metrics}}), 2, "There are exactly two metrics");
|
||||
|
||||
my ($lineCoverage) = grep { $_->{name} eq "lineCoverage" } @{$dat->{metrics}};
|
||||
my ($maxResident) = grep { $_->{name} eq "maxResident" } @{$dat->{metrics}};
|
||||
|
||||
subtest "verifying the lineCoverage metric" => sub {
|
||||
is($lineCoverage->{name}, "lineCoverage", "The name matches.");
|
||||
is($lineCoverage->{value}, 18, "The value matches.");
|
||||
is($lineCoverage->{unit}, "%", "The unit matches.");
|
||||
};
|
||||
|
||||
subtest "verifying the maxResident metric" => sub {
|
||||
is($maxResident->{name}, "maxResident", "The name matches.");
|
||||
is($maxResident->{value}, 27, "The value matches.");
|
||||
is($maxResident->{unit}, "KiB", "The unit matches.");
|
||||
};
|
||||
};
|
||||
|
||||
subtest "Validate the products match" => sub {
|
||||
is(scalar(@{$dat->{outputs}}), 2, "There are exactly two outputs");
|
||||
|
||||
subtest "product: out" => sub {
|
||||
my ($product) = grep { $_->{name} eq "my-build-product" } @{$dat->{products}};
|
||||
my $expectedproduct = $build->buildproducts->find({name => "my-build-product"});
|
||||
|
||||
is($product->{name}, "my-build-product", "The build product is named correctly.");
|
||||
is($product->{subtype}, "", "The subtype is empty.");
|
||||
is($product->{productNr}, $expectedproduct->productnr, "The product number matches.");
|
||||
is($product->{defaultPath}, "", "The default path matches.");
|
||||
is($product->{path}, $expectedproduct->path, "The path matches the output.");
|
||||
is($product->{fileSize}, undef, "The fileSize is undefined for the nix-build output type.");
|
||||
is($product->{sha256hash}, undef, "The sha256hash is undefined for the nix-build output type.");
|
||||
};
|
||||
|
||||
subtest "output: bin" => sub {
|
||||
my ($product) = grep { $_->{name} eq "my-build-product-bin" } @{$dat->{products}};
|
||||
my $expectedproduct = $build->buildproducts->find({name => "my-build-product-bin"});
|
||||
|
||||
is($product->{name}, "my-build-product-bin", "The build product is named correctly.");
|
||||
is($product->{subtype}, "bin", "The subtype matches the output name");
|
||||
is($product->{productNr}, $expectedproduct->productnr, "The product number matches.");
|
||||
is($product->{defaultPath}, "", "The default path matches.");
|
||||
is($product->{path}, $expectedproduct->path, "The path matches the output.");
|
||||
is($product->{fileSize}, undef, "The fileSize is undefined for the nix-build output type.");
|
||||
is($product->{sha256hash}, undef, "The sha256hash is undefined for the nix-build output type.");
|
||||
};
|
||||
};
|
||||
|
||||
done_testing;
|
177
t/Hydra/Plugin/RunCommand/matcher.t
Normal file
177
t/Hydra/Plugin/RunCommand/matcher.t
Normal file
@ -0,0 +1,177 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
use Setup;
|
||||
use Test2::V0;
|
||||
use Hydra::Plugin::RunCommand;
|
||||
|
||||
subtest "isEnabled" => sub {
|
||||
is(
|
||||
Hydra::Plugin::RunCommand::isEnabled({}),
|
||||
"",
|
||||
"Disabled by default."
|
||||
);
|
||||
|
||||
is(
|
||||
Hydra::Plugin::RunCommand::isEnabled({ config => {}}),
|
||||
"",
|
||||
"Disabled by default."
|
||||
);
|
||||
|
||||
is(
|
||||
Hydra::Plugin::RunCommand::isEnabled({ config => { runcommand => {}}}),
|
||||
1,
|
||||
"Enabled if any runcommand blocks exist."
|
||||
);
|
||||
};
|
||||
|
||||
subtest "configSectionMatches" => sub {
|
||||
subtest "Expected matches" => sub {
|
||||
my @examples = (
|
||||
# Exact match
|
||||
["project:jobset:job", "project", "jobset", "job"],
|
||||
|
||||
# One wildcard
|
||||
["project:jobset:*", "project", "jobset", "job"],
|
||||
["project:*:job", "project", "jobset", "job"],
|
||||
["*:jobset:job", "project", "jobset", "job"],
|
||||
|
||||
# Two wildcards
|
||||
["project:*:*", "project", "jobset", "job"],
|
||||
["*:*:job", "project", "jobset", "job"],
|
||||
|
||||
# Three wildcards
|
||||
["*:*:*", "project", "jobset", "job"],
|
||||
|
||||
# Implicit wildcards
|
||||
["", "project", "jobset", "job"],
|
||||
["project", "project", "jobset", "job"],
|
||||
["project:jobset", "project", "jobset", "job"],
|
||||
);
|
||||
|
||||
for my $example (@examples) {
|
||||
my ($matcher, $project, $jobset, $job) = @$example;
|
||||
|
||||
is(
|
||||
Hydra::Plugin::RunCommand::configSectionMatches(
|
||||
$matcher, $project, $jobset, $job
|
||||
),
|
||||
1,
|
||||
"Expecting $matcher to match $project:$jobset:$job"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
subtest "Fails to match" => sub {
|
||||
my @examples = (
|
||||
# Literal string non-matches
|
||||
["project:jobset:job", "project", "jobset", "nonmatch"],
|
||||
["project:jobset:job", "project", "nonmatch", "job"],
|
||||
["project:jobset:job", "nonmatch", "jobset", "job"],
|
||||
|
||||
# Wildcard based non-matches
|
||||
["*:*:job", "project", "jobset", "nonmatch"],
|
||||
["*:jobset:*", "project", "nonmatch", "job"],
|
||||
["project:*:*", "nonmatch", "jobset", "job"],
|
||||
|
||||
# These wildcards are NOT regular expressions
|
||||
["*:*:j.*", "project", "jobset", "job"],
|
||||
[".*:.*:.*", "project", "nonmatch", "job"],
|
||||
);
|
||||
|
||||
for my $example (@examples) {
|
||||
my ($matcher, $project, $jobset, $job) = @$example;
|
||||
|
||||
is(
|
||||
Hydra::Plugin::RunCommand::configSectionMatches(
|
||||
$matcher, $project, $jobset, $job
|
||||
),
|
||||
0,
|
||||
"Expecting $matcher to not match $project:$jobset:$job"
|
||||
);
|
||||
}
|
||||
|
||||
like(
|
||||
dies {
|
||||
Hydra::Plugin::RunCommand::configSectionMatches(
|
||||
"foo:bar:baz:tux", "foo", "bar", "baz"
|
||||
),
|
||||
},
|
||||
qr/invalid section name/,
|
||||
"A matcher must have no more than 3 sections"
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
subtest "eventMatches" => sub {
|
||||
# This is probably a misfeature that isn't very useful but let's test
|
||||
# it anyway. At best this lets you make a RunCommand event not work
|
||||
# by specifying the "events" key. Note: By testing it I'm not promising
|
||||
# it'll keep working. In fact, I wouldn't be surprised if we chose to
|
||||
# delete this support since RunCommand never runs on any event other
|
||||
# than buildFinished.
|
||||
is(
|
||||
Hydra::Plugin::RunCommand::eventMatches({}, "buildFinished"),
|
||||
1,
|
||||
"An unspecified events key matches"
|
||||
);
|
||||
|
||||
is(
|
||||
Hydra::Plugin::RunCommand::eventMatches({ events => ""}, "buildFinished"),
|
||||
0,
|
||||
"An empty events key does not match"
|
||||
);
|
||||
|
||||
is(
|
||||
Hydra::Plugin::RunCommand::eventMatches({ events => "foo bar buildFinished baz"}, "buildFinished"),
|
||||
1,
|
||||
"An events key with multiple events does match when buildFinished is present"
|
||||
);
|
||||
|
||||
is(
|
||||
Hydra::Plugin::RunCommand::eventMatches({ events => "foo bar baz"}, "buildFinished"),
|
||||
0,
|
||||
"An events key with multiple events does not match when buildFinished is missing"
|
||||
);
|
||||
};
|
||||
|
||||
subtest "fanoutToCommands" => sub {
|
||||
my $config = {
|
||||
runcommand => [
|
||||
{
|
||||
job => "",
|
||||
command => "foo"
|
||||
},
|
||||
{
|
||||
job => "project:*:*",
|
||||
command => "bar"
|
||||
},
|
||||
{
|
||||
job => "project:jobset:nomatch",
|
||||
command => "baz"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
is(
|
||||
Hydra::Plugin::RunCommand::fanoutToCommands(
|
||||
$config,
|
||||
"buildFinished",
|
||||
"project",
|
||||
"jobset",
|
||||
"job"
|
||||
),
|
||||
[
|
||||
{
|
||||
matcher => "",
|
||||
command => "foo"
|
||||
},
|
||||
{
|
||||
matcher => "project:*:*",
|
||||
command => "bar"
|
||||
}
|
||||
],
|
||||
"fanoutToCommands returns a command per matching job"
|
||||
);
|
||||
};
|
||||
|
||||
done_testing;
|
Reference in New Issue
Block a user