From 64a3e75c10c868713f4ec512c4475e9e028b0df9 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Mon, 5 Apr 2021 19:29:45 +0000 Subject: [PATCH] Event: init structure and parse existing messages --- src/lib/Hydra/Event.pm | 30 +++++++ src/lib/Hydra/Event/BuildFinished.pm | 25 ++++++ src/lib/Hydra/Event/BuildStarted.pm | 25 ++++++ src/lib/Hydra/Event/StepFinished.pm | 29 +++++++ t/Event.t | 113 +++++++++++++++++++++++++++ 5 files changed, 222 insertions(+) create mode 100644 src/lib/Hydra/Event.pm create mode 100644 src/lib/Hydra/Event/BuildFinished.pm create mode 100644 src/lib/Hydra/Event/BuildStarted.pm create mode 100644 src/lib/Hydra/Event/StepFinished.pm create mode 100644 t/Event.t diff --git a/src/lib/Hydra/Event.pm b/src/lib/Hydra/Event.pm new file mode 100644 index 00000000..ac1222e0 --- /dev/null +++ b/src/lib/Hydra/Event.pm @@ -0,0 +1,30 @@ +package Hydra::Event; + + +use strict; +use Hydra::Event::BuildFinished; +use Hydra::Event::BuildStarted; +use Hydra::Event::StepFinished; +our @ISA = qw(Exporter); +our @EXPORT = qw( + parse_payload +); + +my %channels_to_events = ( + build_started => \&Hydra::Event::BuildStarted::parse, + step_finished => \&Hydra::Event::StepFinished::parse, + build_finished => \&Hydra::Event::BuildFinished::parse, +); + + +sub parse_payload :prototype($$) { + my ($channel_name, $payload) = @_; + my @payload = split /\t/, $payload; + + my $parser = %channels_to_events{$channel_name}; + unless (defined $parser) { + die "Invalid channel name: '$channel_name'"; + } + + return $parser->(@payload); +} diff --git a/src/lib/Hydra/Event/BuildFinished.pm b/src/lib/Hydra/Event/BuildFinished.pm new file mode 100644 index 00000000..50ac2054 --- /dev/null +++ b/src/lib/Hydra/Event/BuildFinished.pm @@ -0,0 +1,25 @@ +package Hydra::Event::BuildFinished; + +use strict; +use warnings; + +sub parse :prototype(@) { + if (@_ == 0) { + die "build_finished: payload takes at least one argument, but ", scalar(@_), " were given"; + } + + my @failures = grep(!/^\d+$/, @_); + if (@failures > 0) { + die "build_finished: payload arguments should be integers, but we received the following non-integers:", @failures; + } + + my ($build_id, @dependents) = map int, @_; + return Hydra::Event::BuildFinished->new($build_id, \@dependents); +} + +sub new { + my ($self, $build_id, $dependencies) = @_; + return bless { "build_id" => $build_id, "dependencies" => $dependencies }, $self; +} + +1; diff --git a/src/lib/Hydra/Event/BuildStarted.pm b/src/lib/Hydra/Event/BuildStarted.pm new file mode 100644 index 00000000..27284387 --- /dev/null +++ b/src/lib/Hydra/Event/BuildStarted.pm @@ -0,0 +1,25 @@ +package Hydra::Event::BuildStarted; + +use strict; +use warnings; + +sub parse :prototype(@) { + unless (@_ == 1) { + die "build_started: payload takes only one argument, but ", scalar(@_), " were given"; + } + + my ($build_id) = @_; + + unless ($build_id =~ /^\d+$/) { + die "build_started: payload argument should be an integer, but '", $build_id, "' was given" + } + + return Hydra::Event::BuildStarted->new(int($build_id)); +} + +sub new { + my ($self, $id) = @_; + return bless { "build_id" => $id }, $self; +} + +1; diff --git a/src/lib/Hydra/Event/StepFinished.pm b/src/lib/Hydra/Event/StepFinished.pm new file mode 100644 index 00000000..0e6d26c1 --- /dev/null +++ b/src/lib/Hydra/Event/StepFinished.pm @@ -0,0 +1,29 @@ +package Hydra::Event::StepFinished; + +use strict; +use warnings; + + +sub parse :prototype(@) { + unless (@_ == 3) { + die "step_finished: payload takes exactly three arguments, but ", scalar(@_), " were given"; + } + + my ($build_id, $step_number, $log_path) = @_; + + unless ($build_id =~ /^\d+$/) { + die "step_finished: payload argument build_id should be an integer, but '", $build_id, "' was given" + } + unless ($step_number =~ /^\d+$/) { + die "step_finished: payload argument step_number should be an integer, but '", $step_number, "' was given" + } + + return Hydra::Event::StepFinished->new(int($build_id), int($step_number), $log_path); +} + +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; +} + +1; diff --git a/t/Event.t b/t/Event.t new file mode 100644 index 00000000..95feb29a --- /dev/null +++ b/t/Event.t @@ -0,0 +1,113 @@ +use strict; +use Hydra::Event; +use Hydra::Event::BuildFinished; +use Hydra::Event::BuildStarted; +use Hydra::Event::StepFinished; + +use Test2::V0; +use Test2::Tools::Exception; + +subtest "Payload type: build_started" => sub { + like( + dies { Hydra::Event::parse_payload("build_started", "") }, + qr/one argument/, + "empty payload" + ); + like( + dies { Hydra::Event::parse_payload("build_started", "abc123\tabc123") }, + qr/only one argument/, + "two arguments" + ); + + like( + dies { Hydra::Event::parse_payload("build_started", "abc123") }, + qr/should be an integer/, + "not an integer" + ); + is( + Hydra::Event::parse_payload("build_started", "19"), + Hydra::Event::BuildStarted->new(19), + "Valid parse" + ); +}; + +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", "") }, + qr/at least one argument/, + "empty payload" + ); + like( + dies { Hydra::Event::parse_payload("build_finished", "abc123") }, + qr/should be integers/, + "build ID should be an integer" + ); + like( + dies { Hydra::Event::parse_payload("build_finished", "123\tabc123") }, + qr/should be integers/, + "dependent ID should be an integer" + ); + is( + Hydra::Event::parse_payload("build_finished", "123"), + Hydra::Event::BuildFinished->new(123, []), + "no dependent builds" + ); + is( + Hydra::Event::parse_payload("build_finished", "123\t456"), + Hydra::Event::BuildFinished->new(123, [456]), + "one dependent build" + ); + is( + Hydra::Event::parse_payload("build_finished", "123\t456\t789\t012\t345"), + Hydra::Event::BuildFinished->new(123, [456, 789, 12, 345]), + "four dependent builds" + ); +}; + + +subtest "Payload type: bogus" => sub { + like( + dies { Hydra::Event::parse_payload("bogus", "") }, + qr/Invalid channel name/, + "bogus channel" + ); +}; + +done_testing;