This is implement in an extremely hacky way due to poor DBIx feature support. Ideally, what we'd need is a way to tell DBIx to ignore the errormsg column unless explicitly requested, and to automatically add a computed 'errormsg IS NULL' column in others. Since it does not support that, this commit instead hacks some support via method overrides while taking care to not break anything obvious.
139 lines
4.8 KiB
Perl
139 lines
4.8 KiB
Perl
use strict;
|
||
use warnings;
|
||
use Setup;
|
||
use Test2::V0;
|
||
use Hydra::Helper::Exec;
|
||
use Data::Dumper;
|
||
|
||
my $ctx = test_context();
|
||
|
||
subtest "general glob testing" => sub {
|
||
my $jobsetCtx = $ctx->makeJobset(
|
||
expression => 'constituents-glob.nix',
|
||
);
|
||
my $jobset = $jobsetCtx->{"jobset"};
|
||
|
||
my ($res, $stdout, $stderr) = captureStdoutStderr(60,
|
||
("hydra-eval-jobset", $jobsetCtx->{"project"}->name, $jobset->name)
|
||
);
|
||
is($res, 0, "hydra-eval-jobset exits zero");
|
||
|
||
my $builds = {};
|
||
for my $build ($jobset->builds) {
|
||
$builds->{$build->job} = $build;
|
||
}
|
||
|
||
subtest "basic globbing works" => sub {
|
||
ok(defined $builds->{"ok_aggregate"}, "'ok_aggregate' is part of the jobset evaluation");
|
||
my @constituents = $builds->{"ok_aggregate"}->constituents->all;
|
||
is(2, scalar @constituents, "'ok_aggregate' has two constituents");
|
||
|
||
my @sortedConstituentNames = sort (map { $_->nixname } @constituents);
|
||
|
||
is($sortedConstituentNames[0], "empty-dir-A", "first constituent of 'ok_aggregate' is 'empty-dir-A'");
|
||
is($sortedConstituentNames[1], "empty-dir-B", "second constituent of 'ok_aggregate' is 'empty-dir-B'");
|
||
};
|
||
|
||
subtest "transitivity is OK" => sub {
|
||
ok(defined $builds->{"indirect_aggregate"}, "'indirect_aggregate' is part of the jobset evaluation");
|
||
my @constituents = $builds->{"indirect_aggregate"}->constituents->all;
|
||
is(1, scalar @constituents, "'indirect_aggregate' has one constituent");
|
||
is($constituents[0]->nixname, "direct_aggregate", "'indirect_aggregate' has 'direct_aggregate' as single constituent");
|
||
};
|
||
};
|
||
|
||
subtest "* selects all except current aggregate" => sub {
|
||
my $jobsetCtx = $ctx->makeJobset(
|
||
expression => 'constituents-glob-all.nix',
|
||
);
|
||
my $jobset = $jobsetCtx->{"jobset"};
|
||
|
||
my ($res, $stdout, $stderr) = captureStdoutStderr(60,
|
||
("hydra-eval-jobset", $jobsetCtx->{"project"}->name, $jobset->name)
|
||
);
|
||
|
||
subtest "no eval errors" => sub {
|
||
ok(utf8::decode($stderr), "Stderr output is UTF8-clean");
|
||
ok(
|
||
$stderr !~ "aggregate job ‘ok_aggregate’ has a constituent .* that doesn't correspond to a Hydra build",
|
||
"Catchall wildcard must not select itself as constituent"
|
||
);
|
||
|
||
$jobset->discard_changes; # refresh from DB
|
||
is(
|
||
$jobset->has_error,
|
||
0,
|
||
"eval-errors non-empty"
|
||
);
|
||
};
|
||
|
||
my $builds = {};
|
||
for my $build ($jobset->builds) {
|
||
$builds->{$build->job} = $build;
|
||
}
|
||
|
||
subtest "two constituents" => sub {
|
||
ok(defined $builds->{"ok_aggregate"}, "'ok_aggregate' is part of the jobset evaluation");
|
||
my @constituents = $builds->{"ok_aggregate"}->constituents->all;
|
||
is(2, scalar @constituents, "'ok_aggregate' has two constituents");
|
||
|
||
my @sortedConstituentNames = sort (map { $_->nixname } @constituents);
|
||
|
||
is($sortedConstituentNames[0], "empty-dir-A", "first constituent of 'ok_aggregate' is 'empty-dir-A'");
|
||
is($sortedConstituentNames[1], "empty-dir-B", "second constituent of 'ok_aggregate' is 'empty-dir-B'");
|
||
};
|
||
};
|
||
|
||
subtest "trivial cycle check" => sub {
|
||
my $jobsetCtx = $ctx->makeJobset(
|
||
expression => 'constituents-cycle.nix',
|
||
);
|
||
my $jobset = $jobsetCtx->{"jobset"};
|
||
|
||
my ($res, $stdout, $stderr) = captureStdoutStderr(60,
|
||
("hydra-eval-jobset", $jobsetCtx->{"project"}->name, $jobset->name)
|
||
);
|
||
|
||
ok(
|
||
$stderr =~ "Found dependency cycle between jobs 'indirect_aggregate' and 'ok_aggregate'",
|
||
"Dependency cycle error is on stderr"
|
||
);
|
||
|
||
ok(utf8::decode($stderr), "Stderr output is UTF8-clean");
|
||
|
||
$jobset->discard_changes({ '+columns' => {'errormsg' => 'errormsg'} }); # refresh from DB
|
||
like(
|
||
$jobset->errormsg,
|
||
qr/Dependency cycle: indirect_aggregate <-> ok_aggregate/,
|
||
"eval-errors non-empty"
|
||
);
|
||
|
||
is(0, $jobset->builds->count, "No builds should be scheduled");
|
||
};
|
||
|
||
subtest "cycle check with globbing" => sub {
|
||
my $jobsetCtx = $ctx->makeJobset(
|
||
expression => 'constituents-cycle-glob.nix',
|
||
);
|
||
my $jobset = $jobsetCtx->{"jobset"};
|
||
|
||
my ($res, $stdout, $stderr) = captureStdoutStderr(60,
|
||
("hydra-eval-jobset", $jobsetCtx->{"project"}->name, $jobset->name)
|
||
);
|
||
|
||
ok(utf8::decode($stderr), "Stderr output is UTF8-clean");
|
||
|
||
$jobset->discard_changes({ '+columns' => {'errormsg' => 'errormsg'} }); # refresh from DB
|
||
like(
|
||
$jobset->errormsg,
|
||
qr/aggregate job ‘indirect_aggregate’ failed with the error: Dependency cycle: indirect_aggregate <-> packages.constituentA/,
|
||
"packages.constituentA error missing"
|
||
);
|
||
|
||
# on this branch of Hydra, hydra-eval-jobset fails hard if an aggregate
|
||
# job is broken.
|
||
is(0, $jobset->builds->count, "Zero jobs are scheduled");
|
||
};
|
||
|
||
done_testing;
|