From 4a1389e36ef5af2513d58eeaa3a5940c453b108f Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Thu, 12 Aug 2021 10:28:35 -0400 Subject: [PATCH] hydra-notify: move StepFinished processing to an Event --- src/lib/Hydra/Event/StepFinished.pm | 32 ++++++++- src/script/hydra-notify | 25 +------ t/Event.t | 38 ----------- t/Event/StepFinished.t | 101 ++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 63 deletions(-) create mode 100644 t/Event/StepFinished.t diff --git a/src/lib/Hydra/Event/StepFinished.pm b/src/lib/Hydra/Event/StepFinished.pm index 0e6d26c1..d14423ad 100644 --- a/src/lib/Hydra/Event/StepFinished.pm +++ b/src/lib/Hydra/Event/StepFinished.pm @@ -23,7 +23,37 @@ sub parse :prototype(@) { sub new :prototype($$$) { my ($self, $build_id, $step_number, $log_path) = @_; - return bless { "build_id" => $build_id, "step_number" => $step_number, "log_path" => $log_path }, $self; + + $log_path = undef if $log_path eq "-"; + + return bless { + "build_id" => $build_id, + "step_number" => $step_number, + "log_path" => $log_path, + "step" => undef, + }, $self; +} + +sub load { + my ($self, $db) = @_; + + if (!defined($self->{"step"})) { + my $build = $db->resultset('Builds')->find($self->{"build_id"}) + or die "build $self->{'build_id'} does not exist\n"; + + $self->{"step"} = $build->buildsteps->find({stepnr => $self->{"step_number"}}) + or die "step $self->{'step_number'} does not exist\n"; + } +} + +sub execute { + my ($self, $db, $plugin) = @_; + + $self->load($db); + + $plugin->stepFinished($self->{"step"}, $self->{"log_path"}); + + return 1; } 1; diff --git a/src/script/hydra-notify b/src/script/hydra-notify index 99618101..7ecb7ddf 100755 --- a/src/script/hydra-notify +++ b/src/script/hydra-notify @@ -75,27 +75,6 @@ sub buildFinished { } } -sub stepFinished { - my ($buildId, $stepNr, $logPath) = @_; - - my $build = $db->resultset('Builds')->find($buildId) - or die "build $buildId does not exist\n"; - - my $step = $build->buildsteps->find({stepnr => $stepNr}) - or die "step $stepNr does not exist\n"; - - $logPath = undef if $logPath eq "-"; - - foreach my $plugin (@plugins) { - eval { - $plugin->stepFinished($step, $logPath); - 1; - } or do { - print STDERR "error with $plugin->stepFinished: $@\n"; - } - } -} - # Process builds that finished while hydra-notify wasn't running. for my $build ($db->resultset('Builds')->search( { notificationpendingsince => { '!=', undef } })) @@ -119,14 +98,12 @@ while (!$queued_only) { my @payload = split /\t/, $payload; eval { - if ($channelName eq "build_started") { + if ($channelName eq "build_started" || $channelName eq "step_finished" ) { my $event = Hydra::Event::new_event($channelName, $message->{"payload"}); runPluginsForEvent($event); } elsif ($channelName eq "build_finished") { my $buildId = int($payload[0]); buildFinished($buildId, @payload[1..$#payload]); - } elsif ($channelName eq "step_finished") { - stepFinished(int($payload[0]), int($payload[1])); } 1; } or do { diff --git a/t/Event.t b/t/Event.t index 7a8023cd..d70c661e 100644 --- a/t/Event.t +++ b/t/Event.t @@ -1,7 +1,6 @@ use strict; use Hydra::Event; use Hydra::Event::BuildFinished; -use Hydra::Event::StepFinished; use Test2::V0; use Test2::Tools::Exception; @@ -14,43 +13,6 @@ subtest "Event: new event" => sub { }; -subtest "Payload type: step_finished" => sub { - like( - dies { Hydra::Event::parse_payload("step_finished", "") }, - qr/three arguments/, - "empty payload" - ); - like( - dies { Hydra::Event::parse_payload("step_finished", "abc123") }, - qr/three arguments/, - "one argument" - ); - like( - dies { Hydra::Event::parse_payload("step_finished", "abc123\tabc123") }, - qr/three arguments/, - "two arguments" - ); - like( - dies { Hydra::Event::parse_payload("step_finished", "abc123\tabc123\tabc123\tabc123") }, - qr/three arguments/, - "four arguments" - ); - like( - dies { Hydra::Event::parse_payload("step_finished", "abc123\t123\t/path/to/log") }, - qr/should be an integer/, - "not an integer: first position" - ); - like( - dies { Hydra::Event::parse_payload("step_finished", "123\tabc123\t/path/to/log") }, - qr/should be an integer/, - "not an integer: second argument" - ); - is( - Hydra::Event::parse_payload("step_finished", "123\t456\t/path/to/logfile"), - Hydra::Event::StepFinished->new(123, 456, "/path/to/logfile") - ); -}; - subtest "Payload type: build_finished" => sub { like( dies { Hydra::Event::parse_payload("build_finished", "") }, diff --git a/t/Event/StepFinished.t b/t/Event/StepFinished.t new file mode 100644 index 00000000..a4bc3fb9 --- /dev/null +++ b/t/Event/StepFinished.t @@ -0,0 +1,101 @@ +use strict; +use Setup; + +my %ctx = test_init(); + +require Hydra::Schema; +require Hydra::Model::DB; +use Hydra::Event; +use Hydra::Event::BuildStarted; + +use Test2::V0; +use Test2::Tools::Exception; +use Test2::Tools::Mock qw(mock_obj); + +my $db = Hydra::Model::DB->new; +hydra_setup($db); + +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"); + +for my $build (queuedBuildsForJobset($jobset)) { + ok(runBuild($build), "Build '".$build->job."' from jobs/basic.nix should exit with return code 0"); +} + + + +subtest "Parsing step_finished" => sub { + like( + dies { Hydra::Event::parse_payload("step_finished", "") }, + qr/three arguments/, + "empty payload" + ); + like( + dies { Hydra::Event::parse_payload("step_finished", "abc123") }, + qr/three arguments/, + "one argument" + ); + like( + dies { Hydra::Event::parse_payload("step_finished", "abc123\tabc123") }, + qr/three arguments/, + "two arguments" + ); + like( + dies { Hydra::Event::parse_payload("step_finished", "abc123\tabc123\tabc123\tabc123") }, + qr/three arguments/, + "four arguments" + ); + like( + dies { Hydra::Event::parse_payload("step_finished", "abc123\t123\t/path/to/log") }, + qr/should be an integer/, + "not an integer: first position" + ); + like( + dies { Hydra::Event::parse_payload("step_finished", "123\tabc123\t/path/to/log") }, + qr/should be an integer/, + "not an integer: second argument" + ); + is( + Hydra::Event::parse_payload("step_finished", "123\t456\t/path/to/logfile"), + Hydra::Event::StepFinished->new(123, 456, "/path/to/logfile") + ); +}; + +subtest "load" => sub { + + my $step = $db->resultset('BuildSteps')->search( + { }, + { limit => 1 } + )->next; + my $build = $step->build; + + my $event = Hydra::Event::StepFinished->new($build->id, $step->stepnr, "/foo/bar/baz"); + + $event->load($db); + is($event->{"step"}->get_column("build"), $build->id, "The build record matches."); + + # Create a fake "plugin" with a stepFinished sub, the sub sets this + # "global" passedStep, passedLogPath variables. + my $passedStep; + my $passedLogPath; + my $plugin = {}; + my $mock = mock_obj $plugin => ( + add => [ + "stepFinished" => sub { + my ($self, $step, $log_path) = @_; + $passedStep = $step; + $passedLogPath = $log_path; + } + ] + ); + + $event->execute($db, $plugin); + + is($passedStep->get_column("build"), $build->id, "The plugin's stepFinished hook is called with a step from the expected build"); + is($passedStep->stepnr, $step->stepnr, "The plugin's stepFinished hook is called with the proper step of the build"); + is($passedLogPath, "/foo/bar/baz", "The plugin's stepFinished hook is called with the proper log path"); +}; + +done_testing;