diff --git a/t/05-scheduler-full.t b/t/05-scheduler-full.t index 5a520ed69a8..12d7e222bcb 100644 --- a/t/05-scheduler-full.t +++ b/t/05-scheduler-full.t @@ -24,6 +24,7 @@ BEGIN { $ENV{FULLSTACK} = 1 if $ENV{SCHEDULER_FULLSTACK}; } +use IPC::Run qw(start); use FindBin; use lib "$FindBin::Bin/lib"; use OpenQA::Constants qw(WORKERS_CHECKER_THRESHOLD DB_TIMESTAMP_ACCURACY); @@ -57,8 +58,9 @@ my $api_secret = $api_credentials->secret; # create web UI and websocket server my $mojoport = $ENV{OPENQA_BASE_PORT} = Mojo::IOLoop::Server->generate_port(); -my $wspid = create_websocket_server($mojoport + 1, 0, 1, 1); +my $ws = create_websocket_server($mojoport + 1, 0, 1, 1); my $webapi = create_webapi($mojoport, sub { }); +my @workers; # setup share and result dir my $sharedir = setup_share_dir($ENV{OPENQA_BASEDIR}); @@ -67,26 +69,33 @@ ok -d $resultdir, "results directory created under $resultdir"; sub create_worker { my ($apikey, $apisecret, $host, $instance, $log) = @_; - my $connect_args = "--instance=${instance} --apikey=${apikey} --apisecret=${apisecret} --host=${host}"; + my @connect_args = ("--instance=${instance}", "--apikey=${apikey}", "--apisecret=${apisecret}", "--host=${host}"); note("Starting standard worker. Instance: $instance for host $host"); + # save testing time as we do not test a webUI host being down for + # multiple minutes + $ENV{OPENQA_WORKER_CONNECT_RETRIES} = 1; + my @cmd = qw(perl ./script/worker --isotovideo=../os-autoinst/isotovideo --verbose); + push @cmd, @connect_args; + return $log ? start \@cmd, \undef, '>&', $log : start \@cmd; +} - my $workerpid = fork(); - if ($workerpid == 0) { - exec("perl ./script/worker $connect_args --isotovideo=../os-autoinst/isotovideo --verbose" - . (defined $log ? " 2>&1 > $log" : "")); - die "FAILED TO START WORKER"; - } - return defined $log ? `pgrep -P $workerpid` : $workerpid; +sub stop_workers { stop_service($_, 1) for @workers } + +sub dead_workers { + my $schema = shift; + $_->update({t_updated => DateTime->from_epoch(epoch => time - WORKERS_CHECKER_THRESHOLD - DB_TIMESTAMP_ACCURACY)}) + for $schema->resultset("Workers")->all(); } +sub scheduler_step { OpenQA::Scheduler::Model::Jobs->singleton->schedule() } + subtest 'Scheduler worker job allocation' => sub { note('try to allocate to previous worker (supposed to fail)'); my $allocated = scheduler_step(); is @$allocated, 0; note('starting two workers'); - my $w1_pid = create_worker($api_key, $api_secret, "http://localhost:$mojoport", 1); - my $w2_pid = create_worker($api_key, $api_secret, "http://localhost:$mojoport", 2); + @workers = map { create_worker($api_key, $api_secret, "http://localhost:$mojoport", $_) } (1, 2); wait_for_worker($schema, 3); wait_for_worker($schema, 4); @@ -103,7 +112,7 @@ subtest 'Scheduler worker job allocation' => sub { ($allocated) = scheduler_step(); is @$allocated, 0; - stop_service($_, 1) for ($w1_pid, $w2_pid); + stop_workers; dead_workers($schema); }; @@ -121,15 +130,15 @@ subtest 're-scheduling and incompletion of jobs when worker rejects jobs or goes is(@$allocated, 0, 'no jobs allocated'); # simulate a worker in broken state; it will register itself but declare itself as broken - my $broken_w_pid = broken_worker($api_key, $api_secret, "http://localhost:$mojoport", 3, 'out of order'); + @workers = broken_worker($api_key, $api_secret, "http://localhost:$mojoport", 3, 'out of order'); wait_for_worker($schema, 5); $allocated = scheduler_step(); is(@$allocated, 0, 'scheduler does not consider broken worker for allocating job'); - stop_service($broken_w_pid, 1); + stop_workers; dead_workers($schema); # simulate a worker in idle state that rejects all jobs assigned to it - my $rejective_w_pid = rejective_worker($api_key, $api_secret, "http://localhost:$mojoport", 3, 'rejection reason'); + @workers = rejective_worker($api_key, $api_secret, "http://localhost:$mojoport", 3, 'rejection reason'); wait_for_worker($schema, 5); note('waiting for job to be assigned and set back to re-scheduled'); @@ -152,12 +161,12 @@ subtest 're-scheduling and incompletion of jobs when worker rejects jobs or goes sleep .2; } ok($job_scheduled, 'assigned job set back to scheduled if worker reports back again but has abandoned the job'); - stop_service($rejective_w_pid, 1); + stop_workers; dead_workers($schema); # start an unstable worker; it will register itself but ignore any job assignment (also not explicitely reject # assignments) - my $unstable_w_pid = unstable_worker($api_key, $api_secret, "http://localhost:$mojoport", 3, -1); + @workers = unstable_worker($api_key, $api_secret, "http://localhost:$mojoport", 3, -1); wait_for_worker($schema, 5); ($allocated) = scheduler_step(); @@ -166,10 +175,10 @@ subtest 're-scheduling and incompletion of jobs when worker rejects jobs or goes and is(@{$allocated}[0]->{worker}, 5, 'job allocated to expected worker'); # kill the worker but assume the job has been actually started and is running - stop_service($unstable_w_pid, 1); + stop_workers; $jobs->find(99982)->update({state => OpenQA::Jobs::Constants::RUNNING}); - $unstable_w_pid = unstable_worker($api_key, $api_secret, "http://localhost:$mojoport", 3, -1); + @workers = unstable_worker($api_key, $api_secret, "http://localhost:$mojoport", 3, -1); wait_for_worker($schema, 5); note('waiting for job to be incompleted'); @@ -185,13 +194,11 @@ subtest 're-scheduling and incompletion of jobs when worker rejects jobs or goes 'running job incompleted if its worker re-connects claiming not to work on it anymore'; like $job->reason, qr/abandoned: associated worker .+:\d+ re-connected but abandoned the job/, 'reason is set'; - stop_service($unstable_w_pid, 1); + stop_workers; dead_workers($schema); }; subtest 'Simulation of heavy unstable load' => sub { - my $allocated; - my @workers; dead_workers($schema); my @duplicated; @@ -201,11 +208,11 @@ subtest 'Simulation of heavy unstable load' => sub { push(@duplicated, $duplicate) if defined $duplicate; } - push(@workers, unresponsive_worker($api_key, $api_secret, "http://localhost:$mojoport", $_)) for (1 .. 50); + @workers = map { unresponsive_worker($api_key, $api_secret, "http://localhost:$mojoport", $_) } (1 .. 50); my $i = 4; wait_for_worker($schema, ++$i) for 1 .. 10; - ($allocated) = scheduler_step(); # Will try to allocate to previous worker and fail! + my $allocated = scheduler_step(); # Will try to allocate to previous worker and fail! is(@$allocated, 10, "Allocated maximum number of jobs that could have been allocated") or die; my %jobs; my %w; @@ -223,16 +230,14 @@ subtest 'Simulation of heavy unstable load' => sub { } is $dup->state, OpenQA::Jobs::Constants::SCHEDULED, "Job(" . $dup->id . ") back in scheduled state"; } - stop_service($_, 1) for @workers; + stop_workers; dead_workers($schema); - @workers = (); - - push(@workers, unstable_worker($api_key, $api_secret, "http://localhost:$mojoport", $_, 3)) for (1 .. 30); - $i = 5; + @workers = map { unstable_worker($api_key, $api_secret, "http://localhost:$mojoport", $_, 3) } (1 .. 30); + $i = 5; wait_for_worker($schema, ++$i) for 0 .. 12; - ($allocated) = scheduler_step(); # Will try to allocate to previous worker and fail! + $allocated = scheduler_step(); # Will try to allocate to previous worker and fail! is @$allocated, 0, "All failed allocation on second step - workers were killed"; for my $dup (@duplicated) { for (0 .. 100) { @@ -242,50 +247,36 @@ subtest 'Simulation of heavy unstable load' => sub { is $dup->state, OpenQA::Jobs::Constants::SCHEDULED, "Job(" . $dup->id . ") is still in scheduled state"; } - stop_service($_, 1) for @workers; + stop_workers; }; subtest 'Websocket server - close connection test' => sub { - stop_service($wspid); + stop_service($ws); local $ENV{OPENQA_LOGFILE}; local $ENV{MOJO_LOG_LEVEL}; - my $log_file = tempfile; - my $unstable_ws_pid = create_websocket_server($mojoport + 1, 1, 0); - my $w2_pid = create_worker($api_key, $api_secret, "http://localhost:$mojoport", 2, $log_file); + my $log; + # create unstable ws + $ws = create_websocket_server($mojoport + 1, 1, 0); + @workers = create_worker($api_key, $api_secret, "http://localhost:$mojoport", 2, \$log); my $found_connection_closed_in_log = 0; - my $log_file_content = ''; - for (my $attempt = 0; $attempt < 300; ++$attempt) { - $log_file_content = $log_file->slurp; - if ($log_file_content =~ qr/.*Websocket connection to .* finished by remote side with code 1008.*/) { + for my $attempt (0 .. 300) { + $log = ''; + $workers[0]->pump; + note "worker out: $log"; + if ($log =~ qr/.*Websocket connection to .* finished by remote side with code 1008.*/) { $found_connection_closed_in_log = 1; last; } - sleep 1; - } - - is($found_connection_closed_in_log, 1, 'closed ws connection logged by worker'); - stop_service($_) for ($unstable_ws_pid, $w2_pid); - dead_workers($schema); - - if (!$found_connection_closed_in_log) { - note('worker log file contained:'); - note($log_file_content); } + is $found_connection_closed_in_log, 1, 'closed ws connection logged by worker'; }; END { - stop_service($_) for ($wspid, $webapi); + stop_workers; + stop_service($_, 1) for ($ws, $webapi); } -sub dead_workers { - my $schema = shift; - $_->update({t_updated => DateTime->from_epoch(epoch => time - WORKERS_CHECKER_THRESHOLD - DB_TIMESTAMP_ACCURACY)}) - for $schema->resultset("Workers")->all(); -} - -sub scheduler_step { OpenQA::Scheduler::Model::Jobs->singleton->schedule() } - done_testing; diff --git a/t/14-grutasks.t b/t/14-grutasks.t index f384234b9ba..674600af3e8 100644 --- a/t/14-grutasks.t +++ b/t/14-grutasks.t @@ -95,7 +95,7 @@ my $t = Test::Mojo->new('OpenQA::WebAPI'); # launch an additional app to serve some file for testing blocking downloads my $mojo_port = Mojo::IOLoop::Server->generate_port; -my $pid = OpenQA::Test::Utils::create_webapi($mojo_port, sub { }); +my $webapi = OpenQA::Test::Utils::create_webapi($mojo_port, sub { }); # define a fix asset_size_limit configuration for this test to be independent of the default value # we possibly want to adjust without going into the details of this test @@ -608,7 +608,8 @@ subtest 'download assets with correct permissions' => sub { ok -f $assetpath, 'asset downloaded'; }; -kill TERM => $pid; +$webapi->signal('TERM'); +$webapi->finish; done_testing(); diff --git a/t/33-developer_mode.t b/t/33-developer_mode.t index 58fbe125512..f50f798a7f4 100644 --- a/t/33-developer_mode.t +++ b/t/33-developer_mode.t @@ -56,12 +56,12 @@ unless (can_load(modules => {'Selenium::Remote::WDKeys' => undef})) { exit(0); } -my $workerpid; -my $wspid; -my $livehandlerpid; -my $schedulerpid; +my $worker; +my $ws; +my $livehandler; +my $scheduler; sub turn_down_stack { - stop_service($_) for ($workerpid, $wspid, $livehandlerpid, $schedulerpid); + stop_service($_) for ($worker, $ws, $livehandler, $scheduler); } # skip if appropriate modules aren't available @@ -94,9 +94,9 @@ ok(Mojolicious::Commands->start_app('OpenQA::WebAPI', 'eval', '1+0')); # start Selenium test driver and other daemons my $mojoport = Mojo::IOLoop::Server->generate_port; my $driver = call_driver(sub { }, {mojoport => $mojoport}); -$wspid = create_websocket_server($mojoport + 1, 0, 0); -$schedulerpid = create_scheduler($mojoport + 3); -$livehandlerpid = create_live_view_handler($mojoport); +$ws = create_websocket_server($mojoport + 1, 0, 0); +$scheduler = create_scheduler($mojoport + 3); +$livehandler = create_live_view_handler($mojoport); # login $driver->title_is('openQA', 'on main page'); @@ -128,7 +128,7 @@ for my $ext (qw(.json .png)) { 'can rename needle ' . $ext); } -$workerpid = start_worker(get_connect_args()); +$worker = start_worker(get_connect_args()); ok wait_for_job_running($driver), 'test 1 is running'; sub wait_for_session_info { diff --git a/t/40-script_load_templates.t b/t/40-script_load_templates.t index fbecc86d7ff..5d5231b7ceb 100644 --- a/t/40-script_load_templates.t +++ b/t/40-script_load_templates.t @@ -55,8 +55,8 @@ $ENV{MOJO_LOG_LEVEL} = 'fatal'; my $mojoport = Mojo::IOLoop::Server->generate_port; $host = "localhost:$mojoport"; my $schema = OpenQA::Test::Database->new->create; -my $pid = OpenQA::Test::Utils::create_webapi($mojoport, sub { }); -END { stop_service $pid; } +my $webapi = OpenQA::Test::Utils::create_webapi($mojoport, sub { }); +END { stop_service $webapi; } # Note: See t/fixtures/03-users.pl for test user credentials my $apikey = 'PERCIVALKEY02'; my $apisecret = 'PERCIVALSECRET02'; diff --git a/t/43-scheduling-and-worker-scalability.t b/t/43-scheduling-and-worker-scalability.t index ddb688e369a..3fa52cf71c3 100644 --- a/t/43-scheduling-and-worker-scalability.t +++ b/t/43-scheduling-and-worker-scalability.t @@ -23,6 +23,7 @@ use File::Path 'make_path'; use Scalar::Util 'looks_like_number'; use Mojo::File 'path'; use Mojo::Util 'dumper'; +use IPC::Run qw(start); use FindBin; use lib "$FindBin::Bin/lib"; use OpenQA::Scheduler::Model::Jobs; @@ -78,8 +79,8 @@ my $workers = $schema->resultset('Workers'); my $jobs = $schema->resultset('Jobs'); # create web UI and websocket server -my $web_socket_server_pid = create_websocket_server($ports{websocket}, 0, 1, 1); -my $webui_pid = create_webapi($ports{webui}, sub { }); +my $web_socket_server = create_websocket_server($ports{websocket}, 0, 1, 1); +my $webui = create_webapi($ports{webui}, sub { }); # prepare spawning workers my $sharedir = setup_share_dir($ENV{OPENQA_BASEDIR}); @@ -103,14 +104,10 @@ sub spawn_worker { my ($instance) = @_; note("Starting worker '$instance'"); - my $workerpid = fork(); - return $workerpid if $workerpid != 0; - - exec('perl', $worker_path, "--instance=$instance", @worker_args); - die "failed to start worker $instance"; + start ['perl', $worker_path, "--instance=$instance", @worker_args]; } my %worker_ids; -my @worker_pids = map { spawn_worker($_) } (1 .. $worker_count); +my @workers = map { spawn_worker($_) } (1 .. $worker_count); # create jobs note("Creating $job_count jobs"); @@ -197,7 +194,7 @@ subtest 'assign and run jobs' => sub { }; subtest 'stop all workers' => sub { - stop_service $_ for @worker_pids; + stop_service $_ for @workers; my @non_offline_workers; for my $try (1 .. $polling_tries_workers) { @non_offline_workers = (); @@ -214,7 +211,7 @@ subtest 'stop all workers' => sub { done_testing; END { - stop_service $_ for @worker_pids; - stop_service $web_socket_server_pid; - stop_service $webui_pid; + stop_service $_ for @workers; + stop_service $web_socket_server; + stop_service $webui; } diff --git a/t/full-stack.t b/t/full-stack.t index 849e6fb8280..df704f0f18c 100644 --- a/t/full-stack.t +++ b/t/full-stack.t @@ -57,16 +57,13 @@ use OpenQA::Test::FullstackUtils; plan skip_all => 'set FULLSTACK=1 (be careful)' unless $ENV{FULLSTACK}; plan skip_all => 'set TEST_PG to e.g. "DBI:Pg:dbname=test" to enable this test' unless $ENV{TEST_PG}; -my $workerpid; -my $wspid; -my $livehandlerpid; +my $worker; +my $ws; +my $livehandler; sub turn_down_stack { - stop_service($_) for ($workerpid, $wspid, $livehandlerpid); -} -sub stop_worker { - is(stop_service($workerpid), $workerpid, 'WORKER is done'); - $workerpid = undef; + stop_service($_) for ($worker, $ws, $livehandler); } +sub stop_worker { stop_service $worker } # skip if appropriate modules aren't available unless (check_driver_modules) { @@ -82,9 +79,9 @@ my $sharedir = setup_share_dir($ENV{OPENQA_BASEDIR}); my $schema = OpenQA::Test::Database->new->create(skip_fixtures => 1, schema_name => 'public', drop_schema => 1); ok(Mojolicious::Commands->start_app('OpenQA::WebAPI', 'eval', '1+0'), 'assets are prefetched'); my $mojoport = Mojo::IOLoop::Server->generate_port; -$wspid = create_websocket_server($mojoport + 1, 0, 0); +$ws = create_websocket_server($mojoport + 1, 0, 0); my $driver = call_driver(sub { }, {mojoport => $mojoport}); -$livehandlerpid = create_live_view_handler($mojoport); +$livehandler = create_live_view_handler($mojoport); my $resultdir = path($ENV{OPENQA_BASEDIR}, 'openqa', 'testresults')->make_path; ok(-d $resultdir, "resultdir \"$resultdir\" exists"); @@ -112,9 +109,8 @@ like(status_text, qr/State: scheduled/, 'test 1 is scheduled'); ok javascript_console_has_no_warnings_or_errors, 'no javascript warnings or errors after test 1 was scheduled'; sub start_worker_and_schedule { - return fail "Unable to start worker, previous worker with PID '$workerpid' is still running" if defined $workerpid; - $workerpid = start_worker(get_connect_args()); - ok($workerpid, "Worker started as $workerpid"); + $worker = start_worker(get_connect_args()); + ok($worker, "Worker started as $worker"); schedule_one_job; } diff --git a/t/lib/OpenQA/SeleniumTest.pm b/t/lib/OpenQA/SeleniumTest.pm index 7fa2f2ec559..5b302239386 100644 --- a/t/lib/OpenQA/SeleniumTest.pm +++ b/t/lib/OpenQA/SeleniumTest.pm @@ -15,6 +15,7 @@ our @EXPORT = qw($drivermissing check_driver_modules enable_timeout wait_until wait_until_element_gone wait_for_element); use Data::Dump 'pp'; +use IPC::Run qw(start); use Mojo::IOLoop::Server; use Mojo::Server::Daemon; use Try::Tiny; @@ -26,8 +27,8 @@ use OpenQA::Test::Utils; use POSIX '_exit'; our $_driver; -our $mojopid; -our $gru_pid; +our $webapi; +our $gru; our $mojoport; our $startingpid = 0; our $drivermissing = 'Install Selenium::Remote::Driver and Selenium::Chrome to run these tests'; @@ -36,19 +37,15 @@ sub _start_app { my ($schema_hook, $args) = @_; $schema_hook = sub { OpenQA::Test::Database->new->create } unless $schema_hook; - $mojoport = $args->{mojoport} // $ENV{MOJO_PORT} // Mojo::IOLoop::Server->generate_port; - $ENV{OPENQA_BASE_PORT} = $mojoport; - + $mojoport = $ENV{OPENQA_BASE_PORT} = $args->{mojoport} // $ENV{MOJO_PORT} // Mojo::IOLoop::Server->generate_port; $startingpid = $$; - $mojopid = OpenQA::Test::Utils::create_webapi($mojoport, $schema_hook); - - _start_gru() if ($args->{with_gru}); + $webapi = OpenQA::Test::Utils::create_webapi($mojoport, $schema_hook); + $gru = _start_gru() if ($args->{with_gru}); return $mojoport; } sub _start_gru { - $gru_pid = fork(); - if ($gru_pid == 0) { + start sub { $0 = 'openqa-gru'; log_info("starting gru\n"); $ENV{MOJO_MODE} = 'test'; @@ -63,9 +60,7 @@ sub _start_gru { }); }); $app->start('gru', 'run', '-m', 'test'); - _exit(0); - } - return $gru_pid; + }; } sub enable_timeout { @@ -392,15 +387,13 @@ sub kill_driver() { $_driver->shutdown_binary; $_driver = undef; } - if ($mojopid) { - kill('TERM', $mojopid); - waitpid($mojopid, 0); - $mojopid = undef; + if ($webapi) { + $webapi->signal('TERM'); + $webapi->finish; } - if ($gru_pid) { - kill('TERM', $gru_pid); - waitpid($gru_pid, 0); - $gru_pid = undef; + if ($gru) { + $gru->signal('TERM'); + $gru->finish; } } diff --git a/t/lib/OpenQA/Test/FullstackUtils.pm b/t/lib/OpenQA/Test/FullstackUtils.pm index 3663a1b4f4f..2d2c6d87d00 100644 --- a/t/lib/OpenQA/Test/FullstackUtils.pm +++ b/t/lib/OpenQA/Test/FullstackUtils.pm @@ -44,13 +44,13 @@ $JOB_SETUP .= ' QEMU_NO_KVM=1' unless -r '/dev/kvm'; sub get_connect_args { my $mojoport = OpenQA::SeleniumTest::get_mojoport; - return "--apikey 1234567890ABCDEF --apisecret 1234567890ABCDEF --host http://localhost:$mojoport"; + return ["--apikey=1234567890ABCDEF", "--apisecret=1234567890ABCDEF", "--host=http://localhost:$mojoport"]; } sub client_output { my ($args) = @_; - my $connect_args = get_connect_args(); - open(my $client, "-|", "perl ./script/openqa-cli api $connect_args $args"); + my @connect_args = @{get_connect_args()}; + open(my $client, "-|", "perl ./script/openqa-cli api @connect_args $args"); my $out; while (<$client>) { $out .= $_; diff --git a/t/lib/OpenQA/Test/Utils.pm b/t/lib/OpenQA/Test/Utils.pm index a1de5804fbd..99582361e52 100644 --- a/t/lib/OpenQA/Test/Utils.pm +++ b/t/lib/OpenQA/Test/Utils.pm @@ -20,6 +20,7 @@ use OpenQA::Scheduler::Client; use Mojo::Home; use Mojo::File qw(path tempfile tempdir); use Cwd qw(abs_path getcwd); +use IPC::Run qw(start); use Mojo::Util 'gzip'; use Test::Output 'combined_like'; use Mojo::IOLoop; @@ -172,11 +173,15 @@ sub redirect_output { } sub stop_service { - my ($pid, $forced) = @_; - return unless $pid; - kill POSIX::SIGTERM => $pid; - kill POSIX::SIGKILL => $pid if $forced; - waitpid($pid, 0); + my ($h, $forced) = @_; + return unless $h; + if ($forced) { + $h->kill_kill(grace => 3); + } + else { + $h->signal('TERM'); + } + $h->finish; } sub wait_for_worker { @@ -197,8 +202,7 @@ sub create_webapi { die 'No schema hook specified' unless $schema_hook; note("Starting WebUI service. Port: $mojoport"); - my $mojopid = fork(); - if ($mojopid == 0) { + my $h = start sub { $0 = 'openqa-webapi'; $schema_hook->(); @@ -207,24 +211,20 @@ sub create_webapi { $daemon->build_app('OpenQA::WebAPI'); $daemon->run; Devel::Cover::report() if Devel::Cover->can('report'); - _exit(0); - } - else { - #$SIG{__DIE__} = sub { kill('TERM', $mojopid); }; - # as this might download assets on first test, we need to wait a while - my $wait = time + 50; - while (time < $wait) { - my $t = time; - my $socket = IO::Socket::INET->new( - PeerHost => '127.0.0.1', - PeerPort => $mojoport, - Proto => 'tcp', - ); - last if $socket; - sleep 1 if time - $t < 1; - } + }; + # as this might download assets on first test, we need to wait a while + my $wait = time + 50; + while (time < $wait) { + my $t = time; + my $socket = IO::Socket::INET->new( + PeerHost => '127.0.0.1', + PeerPort => $mojoport, + Proto => 'tcp', + ); + last if $socket; + sleep 1 if time - $t < 1; } - return $mojopid; + return $h; } sub create_websocket_server { @@ -234,8 +234,7 @@ sub create_websocket_server { note("Bogus: $bogus | No wait: $nowait"); OpenQA::WebSockets::Client->singleton->port($port); - my $wspid = fork(); - if ($wspid == 0) { + my $h = start sub { $0 = 'openqa-websocket'; local $ENV{MOJO_LISTEN} = "http://127.0.0.1:$port"; local $ENV{MOJO_INACTIVITY_TIMEOUT} = 9999; @@ -273,9 +272,8 @@ sub create_websocket_server { OpenQA::WebSockets::run; Devel::Cover::report() if Devel::Cover->can('report'); - _exit(0); - } - elsif (!defined $nowait) { + }; + if (!defined $nowait) { # wait for websocket server my $limit = 20; my $wait = time + $limit; @@ -291,15 +289,14 @@ sub create_websocket_server { } die("websocket server is not responsive after '$limit' seconds") unless time < $wait; } - return $wspid; + return $h; } sub create_scheduler { my ($port, $no_stale_job_detection) = @_; note("Starting Scheduler service. Port: $port"); OpenQA::Scheduler::Client->singleton->port($port); - my $pid = fork(); - if ($pid == 0) { + start sub { $0 = 'openqa-scheduler'; local $ENV{MOJO_LISTEN} = "http://127.0.0.1:$port"; local $ENV{MOJO_INACTIVITY_TIMEOUT} = 9999; @@ -308,24 +305,19 @@ sub create_scheduler { if $no_stale_job_detection; OpenQA::Scheduler::run; Devel::Cover::report() if Devel::Cover->can('report'); - _exit(0); - } - return $pid; + }; } sub create_live_view_handler { my ($mojoport) = @_; - my $pid = fork(); - if ($pid == 0) { + start sub { my $livehandlerport = $mojoport + 2; - my $daemon = Mojo::Server::Daemon->new(listen => ["http://127.0.0.1:$livehandlerport"], silent => 1); $0 = 'openqa-livehandler'; + my $daemon = Mojo::Server::Daemon->new(listen => ["http://127.0.0.1:$livehandlerport"], silent => 1); $daemon->build_app('OpenQA::LiveHandler'); $daemon->run; Devel::Cover::report() if Devel::Cover->can('report'); - _exit(0); - } - return $pid; + }; } sub setup_share_dir { @@ -384,14 +376,12 @@ sub start_worker { my $os_autoinst_path = '../os-autoinst'; my $isotovideo_path = $os_autoinst_path . '/isotovideo'; - my $workerpid = fork(); - return $workerpid unless $workerpid == 0; - $0 = 'openqa-worker'; # save testing time as we do not test a webUI host being down for # multiple minutes $ENV{OPENQA_WORKER_CONNECT_RETRIES} = 1; - exec("perl ./script/worker --instance=1 $connect_args --isotovideo=../os-autoinst/isotovideo --verbose"); - die 'FAILED TO START WORKER'; + my @cmd = qw(perl ./script/worker --isotovideo=../os-autoinst/isotovideo --verbose); + push @cmd, @$connect_args; + start \@cmd; } sub unstable_worker { @@ -400,8 +390,7 @@ sub unstable_worker { note("Starting unstable worker. Instance: $instance for host $host"); $ticks = 1 unless defined $ticks; - my $pid = fork(); - if ($pid == 0) { + my $h = start sub { $0 = 'openqa-worker-unstable'; my $worker = OpenQA::Worker->new( { @@ -422,11 +411,9 @@ sub unstable_worker { if ($sleep) { 1 while sleep $sleep; } - _exit(0); - } + }; sleep $sleep if $sleep; - - return $pid; + return $h; } sub standard_worker { @@ -458,8 +445,7 @@ sub c_worker { my ($apikey, $apisecret, $host, $instance, $bogus, %options) = @_; $bogus //= 1; - my $pid = fork(); - if ($pid == 0) { + start sub { $0 = 'openqa-worker-rejecting'; my $command_handler_mock = Test::MockModule->new('OpenQA::Worker::CommandHandler'); if ($bogus) { @@ -493,10 +479,7 @@ sub c_worker { $worker->exec(); Devel::Cover::report() if Devel::Cover->can('report'); - _exit(0); - } - - return $pid; + }; } sub shared_hash {