139 lines
4.7 KiB
Perl
139 lines
4.7 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->errormsg,
|
|||
|
"",
|
|||
|
"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; # 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; # 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;
|