From 4da80e736ed9977312c05ed684470cac9288d8a5 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Mon, 10 Jan 2022 16:47:57 -0500 Subject: [PATCH 1/5] hydra-eval-jobset: send notifications when cached queued / finished builds are submitted --- src/script/hydra-eval-jobset | 43 +++++++++++++-------- t/scripts/hydra-eval-jobset/notifications.t | 18 ++++++++- 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/src/script/hydra-eval-jobset b/src/script/hydra-eval-jobset index 4848075f..c5d15567 100755 --- a/src/script/hydra-eval-jobset +++ b/src/script/hydra-eval-jobset @@ -399,7 +399,7 @@ sub getPrevJobsetEval { # Check whether to add the build described by $buildInfo. sub checkBuild { - my ($db, $jobset, $inputInfo, $buildInfo, $buildMap, $prevEval, $jobOutPathMap, $plugins) = @_; + my ($db, $jobset, $eval, $inputInfo, $buildInfo, $buildMap, $prevEval, $jobOutPathMap, $plugins) = @_; my @outputNames = sort keys %{$buildInfo->{outputs}}; die unless scalar @outputNames; @@ -435,10 +435,17 @@ sub checkBuild { # the Nixpkgs jobset with PostgreSQL. { jobset_id => $jobset->get_column('id'), job => $jobName, name => $firstOutputName, path => $firstOutputPath }, - { rows => 1, columns => ['id'], join => ['buildoutputs'] }); + { rows => 1, columns => ['id', 'finished'], join => ['buildoutputs'] }); if (defined $prevBuild) { #print STDERR " already scheduled/built as build ", $prevBuild->id, "\n"; $buildMap->{$prevBuild->id} = { id => $prevBuild->id, jobName => $jobName, new => 0, drvPath => $drvPath }; + + if ($prevBuild->finished) { + $db->storage->dbh->do("notify cached_build_finished, ?", undef, "${\$eval->id}\t${\$prevBuild->id}"); + } else { + $db->storage->dbh->do("notify cached_build_queued, ?", undef, "${\$eval->id}\t${\$prevBuild->id}"); + } + return; } } @@ -723,11 +730,24 @@ sub checkJobsetWrapped { # current builds have been added. $jobset->builds->search({iscurrent => 1})->update({iscurrent => 0}); + my $ev = $jobset->jobsetevals->create( + { hash => $argsHash + , evaluationerror => $evaluationErrorRecord + , timestamp => time + , checkouttime => abs(int($checkoutStop - $checkoutStart)) + , evaltime => abs(int($evalStop - $evalStart)) + , hasnewbuilds => 0 + , nrbuilds => 0 + , flake => $flakeRef + , nixexprinput => $jobset->nixexprinput + , nixexprpath => $jobset->nixexprpath + }); + # Schedule each successfully evaluated job. foreach my $job (permute(values %{$jobs})) { next if defined $job->{error}; #print STDERR "considering job " . $project->name, ":", $jobset->name, ":", $job->{jobName} . "\n"; - checkBuild($db, $jobset, $inputInfo, $job, \%buildMap, $prevEval, $jobOutPathMap, $plugins); + checkBuild($db, $jobset, $ev, $inputInfo, $job, \%buildMap, $prevEval, $jobOutPathMap, $plugins); } # Have any builds been added or removed since last time? @@ -735,19 +755,10 @@ sub checkJobsetWrapped { (scalar(grep { $_->{new} } values(%buildMap)) > 0) || (defined $prevEval && $prevEval->jobsetevalmembers->count != scalar(keys %buildMap)); - - my $ev = $jobset->jobsetevals->create( - { hash => $argsHash - , evaluationerror => $evaluationErrorRecord - , timestamp => time - , checkouttime => abs(int($checkoutStop - $checkoutStart)) - , evaltime => abs(int($evalStop - $evalStart)) - , hasnewbuilds => $jobsetChanged ? 1 : 0 - , nrbuilds => $jobsetChanged ? scalar(keys %buildMap) : undef - , flake => $flakeRef - , nixexprinput => $jobset->nixexprinput - , nixexprpath => $jobset->nixexprpath - }); + $ev->update({ + hasnewbuilds => $jobsetChanged ? 1 : 0, + nrbuilds => $jobsetChanged ? scalar(keys %buildMap) : undef + }); $db->storage->dbh->do("notify eval_added, ?", undef, join('\t', $tmpId, $ev->id)); diff --git a/t/scripts/hydra-eval-jobset/notifications.t b/t/scripts/hydra-eval-jobset/notifications.t index cd716779..6cf2a12f 100644 --- a/t/scripts/hydra-eval-jobset/notifications.t +++ b/t/scripts/hydra-eval-jobset/notifications.t @@ -69,7 +69,23 @@ subtest "on a fresh evaluation with changed sources" => sub { ok(evalSucceeds($builds->{"variable-job"}->jobset), "evaluating for the third time"); is($listener->block_for_messages(0)->()->{"channel"}, "eval_started", "the evaluation started"); - is($listener->block_for_messages(0)->()->{"channel"}, "build_queued", "expect only one new build being queued"); + # The order of builds is randomized when writing to the database, + # so we can't expect the list in any specific order here. + is( + [sort( + $listener->block_for_messages(0)->()->{"channel"}, + $listener->block_for_messages(0)->()->{"channel"}, + $listener->block_for_messages(0)->()->{"channel"}, + $listener->block_for_messages(0)->()->{"channel"} + )], + [ + "build_queued", + "cached_build_finished", + "cached_build_finished", + "cached_build_queued", + ], + "we get a notice that a build is queued, one is still queued from a previous eval" + ); is($listener->block_for_messages(0)->()->{"channel"}, "eval_added", "a new evaluation was added"); is($listener->block_for_messages(0)->()->{"channel"}, "builds_added", "a new build was added"); From 96b220089524595265ecf78683cc16ee69fd227c Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Mon, 10 Jan 2022 19:45:57 -0500 Subject: [PATCH 2/5] hydra-notify: sort subscriptions --- src/script/hydra-notify | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/script/hydra-notify b/src/script/hydra-notify index 197652a0..3c929764 100755 --- a/src/script/hydra-notify +++ b/src/script/hydra-notify @@ -93,11 +93,11 @@ my $task_dispatcher = Hydra::TaskDispatcher->new( my $dbh = $db->storage->dbh; my $listener = Hydra::PostgresListener->new($dbh); +$listener->subscribe("build_finished"); $listener->subscribe("build_queued"); $listener->subscribe("build_started"); -$listener->subscribe("build_finished"); -$listener->subscribe("step_finished"); $listener->subscribe("hydra_notify_dump_metrics"); +$listener->subscribe("step_finished"); # Process builds that finished while hydra-notify wasn't running. for my $build ($db->resultset('Builds')->search( From 6b7f1da11e900df8c0162c4b3283e8b63cb84376 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Mon, 10 Jan 2022 20:19:28 -0500 Subject: [PATCH 3/5] hydra-notify: operate on cached_build_finished events --- doc/manual/src/notifications.md | 6 ++ src/lib/Hydra/Event.pm | 2 + src/lib/Hydra/Event/CachedBuildFinished.pm | 59 +++++++++++ src/lib/Hydra/Plugin.pm | 6 ++ src/script/hydra-notify | 1 + t/Event/CachedBuildFinished.t | 111 +++++++++++++++++++++ 6 files changed, 185 insertions(+) create mode 100644 src/lib/Hydra/Event/CachedBuildFinished.pm create mode 100644 t/Event/CachedBuildFinished.t diff --git a/doc/manual/src/notifications.md b/doc/manual/src/notifications.md index 94070771..8d824177 100644 --- a/doc/manual/src/notifications.md +++ b/doc/manual/src/notifications.md @@ -8,6 +8,12 @@ Notifications are passed from `hydra-queue-runner` to `hydra-notify` through Pos Note that the notification format is subject to change and should not be considered an API. Integrate with `hydra-notify` instead of listening directly. +### `cached_build_finished` + +* **Payload:** Exactly two values, tab separated: The ID of the evaluation which contains the finished build, followed by the ID of the finished build. +* **When:** Issued directly after an evaluation completes, when that evaluation includes this finished build. +* **Delivery Semantics:** At most once per evaluation. + ### `build_queued` * **Payload:** Exactly one value, the ID of the build. diff --git a/src/lib/Hydra/Event.pm b/src/lib/Hydra/Event.pm index 99e1a2de..9feb532a 100644 --- a/src/lib/Hydra/Event.pm +++ b/src/lib/Hydra/Event.pm @@ -2,6 +2,7 @@ package Hydra::Event; use strict; use warnings; +use Hydra::Event::CachedBuildFinished; use Hydra::Event::BuildFinished; use Hydra::Event::BuildQueued; use Hydra::Event::BuildStarted; @@ -12,6 +13,7 @@ my %channels_to_events = ( build_started => \&Hydra::Event::BuildStarted::parse, step_finished => \&Hydra::Event::StepFinished::parse, build_finished => \&Hydra::Event::BuildFinished::parse, + cached_build_finished => \&Hydra::Event::CachedBuildFinished::parse, ); diff --git a/src/lib/Hydra/Event/CachedBuildFinished.pm b/src/lib/Hydra/Event/CachedBuildFinished.pm new file mode 100644 index 00000000..dc0f188b --- /dev/null +++ b/src/lib/Hydra/Event/CachedBuildFinished.pm @@ -0,0 +1,59 @@ +package Hydra::Event::CachedBuildFinished; + +use strict; +use warnings; + +sub parse :prototype(@) { + if (@_ != 2) { + die "cached_build_finished: payload takes two arguments, but ", scalar(@_), " were given"; + } + + my @failures = grep(!/^\d+$/, @_); + if (@failures > 0) { + die "cached_build_finished: payload arguments should be integers, but we received the following non-integers:", @failures; + } + + my ($evaluation_id, $build_id) = map int, @_; + return Hydra::Event::CachedBuildFinished->new($evaluation_id, $build_id); +} + +sub new { + my ($self, $evaluation_id, $build_id) = @_; + return bless { + "evaluation_id" => $evaluation_id, + "build_id" => $build_id, + "evaluation" => undef, + "build" => undef, + }, $self; +} + +sub interestedIn { + my ($self, $plugin) = @_; + return int(defined($plugin->can('cachedBuildFinished'))); +} + +sub load { + my ($self, $db) = @_; + + if (!defined($self->{"build"})) { + $self->{"build"} = $db->resultset('Builds')->find($self->{"build_id"}) + or die "build $self->{'build_id'} does not exist\n"; + } + + if (!defined($self->{"evaluation"})) { + $self->{"evaluation"} = $db->resultset('JobsetEvals')->find($self->{"evaluation_id"}) + or die "evaluation $self->{'evaluation_id'} does not exist\n"; + } +} + +sub execute { + my ($self, $db, $plugin) = @_; + + $self->load($db); + + $plugin->cachedBuildFinished($self->{"evaluation"}, $self->{"build"}); + + return 1; +} + +1; diff --git a/src/lib/Hydra/Plugin.pm b/src/lib/Hydra/Plugin.pm index acefc663..5742b3fb 100644 --- a/src/lib/Hydra/Plugin.pm +++ b/src/lib/Hydra/Plugin.pm @@ -36,6 +36,12 @@ sub instantiate { # my ($self, $build) = @_; # } +# # Called when build $build is a finished build, and is +# part evaluation $evaluation +# sub cachedBuildFinished { +# my ($self, $evaluation, $build) = @_; +# } + # # Called when build $build has started. # sub buildStarted { # my ($self, $build) = @_; diff --git a/src/script/hydra-notify b/src/script/hydra-notify index 3c929764..6bc736e9 100755 --- a/src/script/hydra-notify +++ b/src/script/hydra-notify @@ -96,6 +96,7 @@ my $listener = Hydra::PostgresListener->new($dbh); $listener->subscribe("build_finished"); $listener->subscribe("build_queued"); $listener->subscribe("build_started"); +$listener->subscribe("cached_build_finished"); $listener->subscribe("hydra_notify_dump_metrics"); $listener->subscribe("step_finished"); diff --git a/t/Event/CachedBuildFinished.t b/t/Event/CachedBuildFinished.t new file mode 100644 index 00000000..442f1991 --- /dev/null +++ b/t/Event/CachedBuildFinished.t @@ -0,0 +1,111 @@ +use strict; +use warnings; +use Setup; + +my %ctx = test_init(); + +require Hydra::Schema; +require Hydra::Model::DB; +use Hydra::Event; +use Hydra::Event::CachedBuildFinished; + +use Test2::V0; +use Test2::Tools::Exception; +use Test2::Tools::Mock qw(mock_obj); + +my $db = Hydra::Model::DB->new; +hydra_setup($db); + +subtest "Parsing" => sub { + like( + dies { Hydra::Event::parse_payload("cached_build_finished", "") }, + qr/takes two arguments/, + "empty payload" + ); + like( + dies { Hydra::Event::parse_payload("cached_build_finished", "abc123") }, + qr/takes two arguments/, + "missing the build ID" + ); + + like( + dies { Hydra::Event::parse_payload("cached_build_finished", "123\t456\t789\t012\t345") }, + qr/takes two arguments/, + "too many arguments" + ); + like( + dies { Hydra::Event::parse_payload("cached_build_finished", "abc123\tdef456") }, + qr/should be integers/, + "evaluation ID should be an integer" + ); + like( + dies { Hydra::Event::parse_payload("cached_build_finished", "123\tabc123") }, + qr/should be integers/, + "build ID should be an integer" + ); + is( + Hydra::Event::parse_payload("cached_build_finished", "123\t456"), + Hydra::Event::CachedBuildFinished->new(123, 456), + "one dependent build" + ); +}; + +my $project = $db->resultset('Projects')->create({name => "tests", displayname => "", owner => "root"}); +my $jobset = createBaseJobset("basic", "basic.nix", $ctx{jobsdir}); +ok(evalSucceeds($jobset), "Evaluating jobs/basic.nix should exit with return code 0"); +is(nrQueuedBuildsForJobset($jobset), 3, "Evaluating jobs/basic.nix should result in 3 builds"); + +subtest "interested" => sub { + my $event = Hydra::Event::CachedBuildFinished->new(123, 456); + + subtest "A plugin which does not implement the API" => sub { + my $plugin = {}; + my $mock = mock_obj $plugin => (); + + is($event->interestedIn($plugin), 0, "The plugin is not interesting."); + }; + + subtest "A plugin which does implement the API" => sub { + my $plugin = {}; + my $mock = mock_obj $plugin => ( + add => [ + "cachedBuildFinished" => sub {} + ] + ); + + is($event->interestedIn($plugin), 1, "The plugin is interesting."); + }; +}; + +subtest "load" => sub { + my ($build) = $db->resultset('Builds')->search({ }, { limit => 1 })->single; + my $evaluation = $build->jobsetevals->search({}, { limit => 1 })->single; + + my $event = Hydra::Event::CachedBuildFinished->new($evaluation->id, $build->id); + + $event->load($db); + is($event->{"evaluation"}->id, $evaluation->id, "The evaluation record matches."); + is($event->{"build"}->id, $build->id, "The build record matches."); + + # Create a fake "plugin" with a cachedBuildFinished sub, the sub sets this + # global passedEvaluation and passedBuild variables for verifying. + my $passedEvaluation; + my $passedBuild; + my $plugin = {}; + my $mock = mock_obj $plugin => ( + add => [ + "cachedBuildFinished" => sub { + my ($self, $evaluation, $build) = @_; + $passedEvaluation = $evaluation; + $passedBuild = $build; + } + ] + ); + + $event->execute($db, $plugin); + + is($passedEvaluation->id, $evaluation->id, "The plugin's cachedBuildFinished hook is called with a matching evaluation"); + is($passedBuild->id, $build->id, "The plugin's cachedBuildFinished hook is called with a matching build"); +}; + +done_testing; From 42edd3a9d8165b1cf544be6149ccc8abda6c10e2 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Mon, 10 Jan 2022 20:23:48 -0500 Subject: [PATCH 4/5] hydra-notify: respond to cached_build_queued --- doc/manual/src/notifications.md | 7 ++ src/lib/Hydra/Event.pm | 2 + src/lib/Hydra/Event/CachedBuildQueued.pm | 59 ++++++++++++ src/lib/Hydra/Plugin.pm | 6 ++ src/script/hydra-notify | 1 + t/Event/CachedBuildQueued.t | 111 +++++++++++++++++++++++ 6 files changed, 186 insertions(+) create mode 100644 src/lib/Hydra/Event/CachedBuildQueued.pm create mode 100644 t/Event/CachedBuildQueued.t diff --git a/doc/manual/src/notifications.md b/doc/manual/src/notifications.md index 8d824177..2423670c 100644 --- a/doc/manual/src/notifications.md +++ b/doc/manual/src/notifications.md @@ -14,6 +14,13 @@ Note that the notification format is subject to change and should not be conside * **When:** Issued directly after an evaluation completes, when that evaluation includes this finished build. * **Delivery Semantics:** At most once per evaluation. + +### `cached_build_queued` + +* **Payload:** Exactly two values, tab separated: The ID of the evaluation which contains the finished build, followed by the ID of the queued build. +* **When:** Issued directly after an evaluation completes, when that evaluation includes this queued build. +* **Delivery Semantics:** At most once per evaluation. + ### `build_queued` * **Payload:** Exactly one value, the ID of the build. diff --git a/src/lib/Hydra/Event.pm b/src/lib/Hydra/Event.pm index 9feb532a..9efeda67 100644 --- a/src/lib/Hydra/Event.pm +++ b/src/lib/Hydra/Event.pm @@ -3,6 +3,7 @@ package Hydra::Event; use strict; use warnings; use Hydra::Event::CachedBuildFinished; +use Hydra::Event::CachedBuildQueued; use Hydra::Event::BuildFinished; use Hydra::Event::BuildQueued; use Hydra::Event::BuildStarted; @@ -14,6 +15,7 @@ my %channels_to_events = ( step_finished => \&Hydra::Event::StepFinished::parse, build_finished => \&Hydra::Event::BuildFinished::parse, cached_build_finished => \&Hydra::Event::CachedBuildFinished::parse, + cached_build_queued => \&Hydra::Event::CachedBuildQueued::parse, ); diff --git a/src/lib/Hydra/Event/CachedBuildQueued.pm b/src/lib/Hydra/Event/CachedBuildQueued.pm new file mode 100644 index 00000000..7e4aa5ba --- /dev/null +++ b/src/lib/Hydra/Event/CachedBuildQueued.pm @@ -0,0 +1,59 @@ +package Hydra::Event::CachedBuildQueued; + +use strict; +use warnings; + +sub parse :prototype(@) { + if (@_ != 2) { + die "cached_build_queued: payload takes two arguments, but ", scalar(@_), " were given"; + } + + my @failures = grep(!/^\d+$/, @_); + if (@failures > 0) { + die "cached_build_queued: payload arguments should be integers, but we received the following non-integers:", @failures; + } + + my ($evaluation_id, $build_id) = map int, @_; + return Hydra::Event::CachedBuildQueued->new($evaluation_id, $build_id); +} + +sub new { + my ($self, $evaluation_id, $build_id) = @_; + return bless { + "evaluation_id" => $evaluation_id, + "build_id" => $build_id, + "evaluation" => undef, + "build" => undef, + }, $self; +} + +sub interestedIn { + my ($self, $plugin) = @_; + return int(defined($plugin->can('cachedBuildQueued'))); +} + +sub load { + my ($self, $db) = @_; + + if (!defined($self->{"build"})) { + $self->{"build"} = $db->resultset('Builds')->find($self->{"build_id"}) + or die "build $self->{'build_id'} does not exist\n"; + } + + if (!defined($self->{"evaluation"})) { + $self->{"evaluation"} = $db->resultset('JobsetEvals')->find($self->{"evaluation_id"}) + or die "evaluation $self->{'evaluation_id'} does not exist\n"; + } +} + +sub execute { + my ($self, $db, $plugin) = @_; + + $self->load($db); + + $plugin->cachedBuildQueued($self->{"evaluation"}, $self->{"build"}); + + return 1; +} + +1; diff --git a/src/lib/Hydra/Plugin.pm b/src/lib/Hydra/Plugin.pm index 5742b3fb..b42e4b4c 100644 --- a/src/lib/Hydra/Plugin.pm +++ b/src/lib/Hydra/Plugin.pm @@ -36,6 +36,12 @@ sub instantiate { # my ($self, $build) = @_; # } +# # Called when build $build has been queued again by evaluation $evaluation +# where $build has not yet finished. +# sub cachedBuildQueued { +# my ($self, $evaluation, $build) = @_; +# } + # # Called when build $build is a finished build, and is # part evaluation $evaluation # sub cachedBuildFinished { diff --git a/src/script/hydra-notify b/src/script/hydra-notify index 6bc736e9..04130f4f 100755 --- a/src/script/hydra-notify +++ b/src/script/hydra-notify @@ -97,6 +97,7 @@ $listener->subscribe("build_finished"); $listener->subscribe("build_queued"); $listener->subscribe("build_started"); $listener->subscribe("cached_build_finished"); +$listener->subscribe("cached_build_queued"); $listener->subscribe("hydra_notify_dump_metrics"); $listener->subscribe("step_finished"); diff --git a/t/Event/CachedBuildQueued.t b/t/Event/CachedBuildQueued.t new file mode 100644 index 00000000..780b568f --- /dev/null +++ b/t/Event/CachedBuildQueued.t @@ -0,0 +1,111 @@ +use strict; +use warnings; +use Setup; + +my %ctx = test_init(); + +require Hydra::Schema; +require Hydra::Model::DB; +use Hydra::Event; +use Hydra::Event::CachedBuildQueued; + +use Test2::V0; +use Test2::Tools::Exception; +use Test2::Tools::Mock qw(mock_obj); + +my $db = Hydra::Model::DB->new; +hydra_setup($db); + +subtest "Parsing" => sub { + like( + dies { Hydra::Event::parse_payload("cached_build_queued", "") }, + qr/takes two arguments/, + "empty payload" + ); + like( + dies { Hydra::Event::parse_payload("cached_build_queued", "abc123") }, + qr/takes two arguments/, + "missing the build ID" + ); + + like( + dies { Hydra::Event::parse_payload("cached_build_queued", "123\t456\t789\t012\t345") }, + qr/takes two arguments/, + "too many arguments" + ); + like( + dies { Hydra::Event::parse_payload("cached_build_queued", "abc123\tdef456") }, + qr/should be integers/, + "evaluation ID should be an integer" + ); + like( + dies { Hydra::Event::parse_payload("cached_build_queued", "123\tabc123") }, + qr/should be integers/, + "build ID should be an integer" + ); + is( + Hydra::Event::parse_payload("cached_build_queued", "123\t456"), + Hydra::Event::CachedBuildQueued->new(123, 456), + "one dependent build" + ); +}; + +my $project = $db->resultset('Projects')->create({name => "tests", displayname => "", owner => "root"}); +my $jobset = createBaseJobset("basic", "basic.nix", $ctx{jobsdir}); +ok(evalSucceeds($jobset), "Evaluating jobs/basic.nix should exit with return code 0"); +is(nrQueuedBuildsForJobset($jobset), 3, "Evaluating jobs/basic.nix should result in 3 builds"); + +subtest "interested" => sub { + my $event = Hydra::Event::CachedBuildQueued->new(123, 456); + + subtest "A plugin which does not implement the API" => sub { + my $plugin = {}; + my $mock = mock_obj $plugin => (); + + is($event->interestedIn($plugin), 0, "The plugin is not interesting."); + }; + + subtest "A plugin which does implement the API" => sub { + my $plugin = {}; + my $mock = mock_obj $plugin => ( + add => [ + "cachedBuildQueued" => sub {} + ] + ); + + is($event->interestedIn($plugin), 1, "The plugin is interesting."); + }; +}; + +subtest "load" => sub { + my ($build) = $db->resultset('Builds')->search({ }, { limit => 1 })->single; + my $evaluation = $build->jobsetevals->search({}, { limit => 1 })->single; + + my $event = Hydra::Event::CachedBuildQueued->new($evaluation->id, $build->id); + + $event->load($db); + is($event->{"evaluation"}->id, $evaluation->id, "The evaluation record matches."); + is($event->{"build"}->id, $build->id, "The build record matches."); + + # Create a fake "plugin" with a cachedBuildQueued sub, the sub sets this + # global passedEvaluation and passedBuild variables for verifying. + my $passedEvaluation; + my $passedBuild; + my $plugin = {}; + my $mock = mock_obj $plugin => ( + add => [ + "cachedBuildQueued" => sub { + my ($self, $evaluation, $build) = @_; + $passedEvaluation = $evaluation; + $passedBuild = $build; + } + ] + ); + + $event->execute($db, $plugin); + + is($passedEvaluation->id, $evaluation->id, "The plugin's cachedBuildQueued hook is called with a matching evaluation"); + is($passedBuild->id, $build->id, "The plugin's cachedBuildQueued hook is called with a matching build"); +}; + +done_testing; From 6d5b234ba2705f1bb67da522ab606a26f249eb75 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Tue, 11 Jan 2022 14:29:05 -0500 Subject: [PATCH 5/5] hydra-eval-jobset/notification.t: comment which jobs produced which messages I tried to write the test in such a way to assert the content matched what we expected, but since the ordering of them is not known, it is quite tricky to write. --- t/scripts/hydra-eval-jobset/notifications.t | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/t/scripts/hydra-eval-jobset/notifications.t b/t/scripts/hydra-eval-jobset/notifications.t index 6cf2a12f..d0bbb3af 100644 --- a/t/scripts/hydra-eval-jobset/notifications.t +++ b/t/scripts/hydra-eval-jobset/notifications.t @@ -79,9 +79,17 @@ subtest "on a fresh evaluation with changed sources" => sub { $listener->block_for_messages(0)->()->{"channel"} )], [ + # The `variable-job` build since it is the only one that is + # totally different in this evaluation. "build_queued", + + # The next two are `stable-job-passing` and `stable-job-failing`, + # since those are the two we explicitly built above "cached_build_finished", "cached_build_finished", + + # Finally, this should be `stable-job-queued` since we never + # built it. "cached_build_queued", ], "we get a notice that a build is queued, one is still queued from a previous eval"