Skip to content

Commit

Permalink
Move loop into CommandHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
kalikiana committed Nov 10, 2022
1 parent 64f6e9b commit 84e7d7d
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 53 deletions.
55 changes: 53 additions & 2 deletions OpenQA/Isotovideo/CommandHandler.pm
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@ package OpenQA::Isotovideo::CommandHandler;
use Mojo::Base 'Mojo::EventEmitter', -signatures;

use bmwqemu;
use testapi 'diag';
use log qw(diag fctwarn);
use OpenQA::Isotovideo::Interface;
use OpenQA::Isotovideo::NeedleDownloader;
use Cpanel::JSON::XS;
use Mojo::File 'path';
use IO::Select;
use Time::HiRes qw(gettimeofday tv_interval);

use constant AUTOINST_STATUSFILE => 'autoinst-status.json';


# io handles for sending data to command server and backend
has [qw(test_fd cmd_srv_fd backend_fd answer_fd)] => undef;
has [qw(test_fd cmd_srv_fd backend_fd backend_out_fd answer_fd)] => undef;

# the name of the current test (full name includes category prefix, eg. installation-)
has [qw(current_test_name current_test_full_name)];
Expand All @@ -37,6 +39,8 @@ has pause_on_next_command => sub { $bmwqemu::vars{PAUSE_ON_NEXT_COMMAND} // 0 };

# the reason why the test execution has paused or 0 if not paused
has reason_for_pause => 0;
# the loop status
has loop => 1;

# when paused, save the command from autotest which has been postponed to be able to resume
has postponed_answer_fd => undef;
Expand Down Expand Up @@ -64,6 +68,19 @@ sub new ($class, @args) {
$self->last_check_microseconds($last_check_microseconds);
}

sub setup_signal_handler ($self) {
my $signal_handler = sub ($sig) { $self->_signal_handler($sig) };
$SIG{TERM} = $signal_handler;
$SIG{INT} = $signal_handler;
$SIG{HUP} = $signal_handler;
}

sub _signal_handler ($self, $sig) {
bmwqemu::serialize_state(component => 'isotovideo', msg => "isotovideo received signal $sig", log => 1);
return $self->loop(0) if $self->loop;
$self->emit(signal => $sig);
}

sub clear_tags_and_timeout ($self) {
$self->tags(undef);
$self->timeout(undef);
Expand Down Expand Up @@ -274,6 +291,7 @@ sub _handle_command_tests_done ($self, $response, @) {
$self->test_died($response->{died});
$self->test_completed($response->{completed});
$self->emit(tests_done => $response);
$self->loop(0);
$self->current_test_name('');
$self->status('finished');
$self->update_status_file;
Expand Down Expand Up @@ -395,4 +413,37 @@ sub check_asserted_screen ($self) {
}
}

sub _read_response ($self, $rsp, $fd) {
if (!defined $rsp) {
fctwarn sprintf("THERE IS NOTHING TO READ %d %d %d", fileno($fd), fileno($self->test_fd), fileno($self->cmd_srv_fd));
$self->loop(0);
} elsif ($fd == $self->backend_out_fd) {
$self->send_to_backend_requester({ret => $rsp->{rsp}});
} else {
$self->process_command($fd, $rsp);
}
}

sub run ($self) {
# now we have everything, give the tests a go
$self->test_fd->write("GO\n");

my $io_select = IO::Select->new();
$io_select->add($self->test_fd);
$io_select->add($self->cmd_srv_fd);
$io_select->add($self->backend_out_fd);

while ($self->loop) {
my ($ready_for_read, $ready_for_write, $exceptions) = IO::Select::select($io_select, undef, $io_select, $self->timeout);
for my $readable (@$ready_for_read) {
my $rsp = myjsonrpc::read_json($readable);
$self->_read_response($rsp, $readable);
last unless defined $rsp;
}
$self->check_asserted_screen if defined($self->tags);
}
$self->stop_command_processing;
return 0;
}

1;
63 changes: 12 additions & 51 deletions isotovideo
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ BEGIN {
unshift @INC, "$installprefix";
}

use log qw(diag fctwarn);
use log qw(diag);
use needle;
use autotest ();
use commands;
Expand All @@ -76,7 +76,6 @@ use Getopt::Long;
require IPC::System::Simple;
use POSIX qw(:sys_wait_h _exit);
use Try::Tiny;
use IO::Select;
use Mojo::File qw(curfile);
use Mojo::UserAgent;
use Mojo::IOLoop::ReadWriteProcess 'process';
Expand Down Expand Up @@ -155,7 +154,6 @@ my $command_handler;
my $testprocess;
my $cmd_srv_fd;
my $cmd_srv_port;
my $loop = 1;

# note: The subsequently defined stop_* functions are used to tear down the process tree.
# However, the worker also ensures that all processes are being terminated (and
Expand Down Expand Up @@ -199,19 +197,6 @@ sub stop_autotest () {
diag('done with autotest process');
}

sub signalhandler ($sig) {
bmwqemu::serialize_state(component => 'isotovideo', msg => "isotovideo received signal $sig", log => 1);
return $loop = 0 if $loop;
$backend->stop if defined $backend;
stop_commands("received signal $sig");
stop_autotest;
_exit(1);
}

$SIG{TERM} = \&signalhandler;
$SIG{INT} = \&signalhandler;
$SIG{HUP} = \&signalhandler;

# make sure all commands coming from the backend will not be in the
# developers's locale - but a defined english one. This is SUSE's
# default locale
Expand Down Expand Up @@ -261,58 +246,34 @@ $backend = OpenQA::Isotovideo::Backend->new;

spawn_debuggers;

my $io_select = IO::Select->new();
$io_select->add($testfd);
$io_select->add($cmd_srv_fd);
$io_select->add($backend->process->channel_out);

# stop main loop as soon as one of the child processes terminates
my $stop_loop = sub (@) { $loop = 0 if $loop; };
my $stop_loop = sub (@) { $command_handler->loop(0) if $command_handler->loop; };
$testprocess->once(collected => $stop_loop);
$backend->process->once(collected => $stop_loop);
$cmd_srv_process->once(collected => $stop_loop);

# now we have everything, give the tests a go
$testfd->write("GO\n");

$command_handler = OpenQA::Isotovideo::CommandHandler->new(
cmd_srv_fd => $cmd_srv_fd,
test_fd => $testfd,
test_fd => $testfd,
backend_fd => $backend->process->channel_in,
backend_out_fd => $backend->process->channel_out,
);
$command_handler->on(tests_done => sub (@) {
CORE::close($testfd);
$testfd = undef;
stop_autotest;
$loop = 0;
});
$command_handler->on(signal => sub ($event, $sig) {
$backend->stop if defined $backend;
stop_commands("received signal $sig");
stop_autotest;
_exit(1);
});
$command_handler->setup_signal_handler;

$return_code = 0;

# enter the main loop: process messages from autotest, command server and backend
while ($loop) {
my ($ready_for_read, $ready_for_write, $exceptions) = IO::Select::select($io_select, undef, $io_select, $command_handler->timeout);
for my $readable (@$ready_for_read) {
my $rsp = myjsonrpc::read_json($readable);
if (!defined $rsp) {
fctwarn sprintf("THERE IS NOTHING TO READ %d %d %d", fileno($readable), fileno($testfd), fileno($cmd_srv_fd));
$readable = 1;
$loop = 0;
last;
}
if ($readable == $backend->process->channel_out) {
$command_handler->send_to_backend_requester({ret => $rsp->{rsp}});
next;
}
$command_handler->process_command($readable, $rsp);
}
$command_handler->check_asserted_screen if defined($command_handler->tags);
}

# tell the command server that it should no longer process isotovideo commands since we've
# just left the loop which would handle such commands (otherwise the command server would just
# hang on the next isotovideo command)
$command_handler->stop_command_processing;
$command_handler->run;

# terminate/kill the command server and let it inform its websocket clients before
stop_commands('test execution ended');
Expand Down
19 changes: 19 additions & 0 deletions t/19-isotovideo-command-processing.t
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,25 @@ subtest check_asserted_screen => sub {
ok($command_handler->timeout, 'Timeout was set');
};

subtest signalhandler => sub {
$command_handler->loop(1);
stderr_like {
$command_handler->_signal_handler('TERM');
} qr/isotovideo received signal TERM/, 'Signal logged';
is($command_handler->loop, 0, 'Loop was stopped');
};

subtest 'No readable JSON' => sub {
# We need valid fd's so fileno works but they're never used
open(my $readable, "$Bin");
$command_handler->test_fd($readable);
$command_handler->cmd_srv_fd($readable);
stderr_like {
$command_handler->_read_response(undef, $readable);
} qr/THERE IS NOTHING TO READ/, 'no response';
is($command_handler->loop, 0, 'Loop was stopped');
};

done_testing;

END {
Expand Down

0 comments on commit 84e7d7d

Please sign in to comment.