From e95705a941992f0d9fb59bdc5ec951c4ce204330 Mon Sep 17 00:00:00 2001 From: Dylan William Hardison Date: Thu, 17 Aug 2017 13:48:51 -0400 Subject: no bug - have the test runners start up the httpd (#203) --- scripts/entrypoint.pl | 227 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 183 insertions(+), 44 deletions(-) (limited to 'scripts') diff --git a/scripts/entrypoint.pl b/scripts/entrypoint.pl index b34384ff1..2d1ef8fe9 100755 --- a/scripts/entrypoint.pl +++ b/scripts/entrypoint.pl @@ -12,26 +12,31 @@ use File::Copy::Recursive qw(dircopy); use Getopt::Long qw(:config gnu_getopt); use LWP::Simple qw(get); use User::pwent; +use POSIX qw(WEXITSTATUS setsid); + +use IO::Async::Loop; +use IO::Async::Process; +use IO::Async::Timer::Periodic; +use IO::Async::Signal; + +use constant CI => $ENV{CI}; my $cmd = shift @ARGV; -my $func = __PACKAGE__->can("cmd_$cmd") // sub { run($cmd, @ARGV) }; +my $func = __PACKAGE__->can("cmd_$cmd") + or die "unknown command: $cmd\n"; +my $opts = __PACKAGE__->can("opt_$cmd") // sub { @ARGV }; fix_path(); check_user(); check_env() unless $cmd eq 'shell'; write_localconfig( localconfig_from_env() ); + $func->(@ARGV); sub cmd_httpd { check_data_dir(); wait_for_db(); - run( '/usr/sbin/httpd', '-DFOREGROUND', - '-f', '/app/httpd/httpd.conf', @_ ); -} -sub cmd_qa_httpd { - copy_qa_extension(); - cmd_httpd('-DHTTPD_IN_SUBDIR', @_); } sub cmd_load_test_data { @@ -39,17 +44,25 @@ sub cmd_load_test_data { die "BZ_QA_ANSWERS_FILE is not set" unless $ENV{BZ_QA_ANSWERS_FILE}; run( 'perl', 'checksetup.pl', '--no-template', $ENV{BZ_QA_ANSWERS_FILE} ); - run( 'perl', 'scripts/generate_bmo_data.pl', - '--user-pref', 'ui_experiments=off' ); - chdir '/app/qa/config'; - say 'chdir(/app/qa/config)'; - run( 'perl', 'generate_test_data.pl' ); + + if ($ENV{BZ_QA_LEGACY_MODE}) { + run( 'perl', 'scripts/generate_bmo_data.pl', + '--user-pref', 'ui_experiments=off' ); + chdir '/app/qa/config'; + say 'chdir(/app/qa/config)'; + run( 'perl', 'generate_test_data.pl' ); + } + else { + run( 'perl', 'scripts/generate_bmo_data.pl' ); + } } sub cmd_test_heartbeat { - my $conf = require $ENV{BZ_QA_CONF_FILE}; - wait_for_httpd($conf->{browser_url}); - my $heartbeat = get("$conf->{browser_url}/__heartbeat__"); + my ($url) = @_; + die "test_heartbeat requires a url!\n" unless $url; + + wait_for_httpd($url); + my $heartbeat = get("$url/__heartbeat__"); if ($heartbeat && $heartbeat =~ /Bugzilla OK/) { exit 0; } @@ -59,33 +72,152 @@ sub cmd_test_heartbeat { } sub cmd_test_webservices { + my $conf = require $ENV{BZ_QA_CONF_FILE}; check_data_dir(); - wait_for_db(); - wait_for_httpd($conf->{browser_url}); - copy_qa_extension(); + my @httpd_cmd = ( '/usr/sbin/httpd', '-DFOREGROUND', '-f', '/app/httpd/httpd.conf' ); + if ($ENV{BZ_QA_LEGACY_MODE}) { + copy_qa_extension(); + push @httpd_cmd, '-DHTTPD_IN_SUBDIR'; + } - chdir('/app/qa/t'); - run( 'prove', '-qf', '-I/app', '-I/app/local/lib/perl5', glob('webservice_*.t') ); + prove_with_httpd( + httpd_url => $conf->{browser_url}, + httpd_cmd => \@httpd_cmd, + prove_cmd => [ + 'prove', '-qf', '-I/app', + '-I/app/local/lib/perl5', + sub { glob('webservice_*.t') }, + ], + prove_dir => '/app/qa/t', + ); } sub cmd_test_selenium { my $conf = require $ENV{BZ_QA_CONF_FILE}; check_data_dir(); - wait_for_db(); - wait_for_httpd($conf->{browser_url}); - copy_qa_extension(); + my @httpd_cmd = ( '/usr/sbin/httpd', '-DFOREGROUND', '-f', '/app/httpd/httpd.conf' ); + if ($ENV{BZ_QA_LEGACY_MODE}) { + copy_qa_extension(); + push @httpd_cmd, '-DHTTPD_IN_SUBDIR'; + } - chdir('/app/qa/t'); - run( 'prove', '-qf', '-Ilib', '-I/app', '-I/app/local/lib/perl5', glob('test_*.t') ); + prove_with_httpd( + httpd_url => $conf->{browser_url}, + httpd_cmd => \@httpd_cmd, + prove_cmd => [ + 'prove', '-qf', '-Ilib', '-I/app', + '-I/app/local/lib/perl5', + sub { glob('test_*.t') } + ], + prove_dir => '/app/qa/t', + ); } +sub cmd_shell { run( 'bash', '-l' ); } +sub cmd_prove { run( "prove", "-I/app", "-I/app/local/lib/perl5", @_ ); } +sub cmd_version { run( 'cat', '/app/version.json' ); } + +sub cmd_test_bmo { + prove_with_httpd( + httpd_url => $ENV{BZ_BASE_URL}, + httpd_cmd => [ '/usr/sbin/httpd', '-f', '/app/httpd/httpd.conf', '-DFOREGROUND' ], + prove_cmd => [ "prove", "-I/app", "-I/app/local/lib/perl5", @_ ], + ); +} + +sub prove_with_httpd { + my (%param) = @_; + + check_data_dir(); + wait_for_db(); + + unless (-d "/app/logs") { + mkdir("/app/logs") or die "unable to mkdir(/app/logs): $!\n"; + } + + my $httpd_cmd = $param{httpd_cmd}; + my $prove_cmd = $param{prove_cmd}; + + my $loop = IO::Async::Loop->new; + + my $httpd_exit_f = $loop->new_future; + warn "starting httpd\n"; + my $httpd = IO::Async::Process->new( + code => sub { + setsid(); + exec(@$httpd_cmd); + }, + setup => [ + stdout => ["open", ">", "/app/logs/access.log"], + stderr => ["open", ">", "/app/logs/error.log"], + ], + on_finish => on_finish($httpd_exit_f), + on_exception => on_exception('httpd', $httpd_exit_f), + ); + $loop->add($httpd); + wait_for_httpd( $httpd, $param{httpd_url} ); + + warn "httpd started, starting prove\n"; + + my $prove_exit_f = $loop->new_future; + my $prove = IO::Async::Process->new( + code => sub { + chdir($param{prove_dir}) if $param{prove_dir}; + my @cmd = (map { ref $_ eq 'CODE' ? $_->() : $_ } @$prove_cmd); + warn "run @cmd\n"; + exec(@cmd); + }, + on_finish => on_finish($prove_exit_f), + on_exception => on_exception('prove', $prove_exit_f), + ); + $loop->add($prove); -sub cmd_shell { run( 'bash', '-l' ); } + my $prove_exit = $prove_exit_f->get(); + if ($httpd->is_running) { + $httpd->kill('TERM'); + my $httpd_exit = $httpd_exit_f->get(); + warn "httpd exit code: $httpd_exit\n" if $httpd_exit != 0; + } + + exit $prove_exit; +} -sub cmd_version { run( 'cat', '/app/version.json' ); } +sub wait_for_httpd { + my ($process, $url) = @_; + my $loop = IO::Async::Loop->new; + my $is_running_f = $loop->new_future; + my $ticks = 0; + my $run_checker = IO::Async::Timer::Periodic->new( + first_interval => 0, + interval => 1, + reschedule => 'hard', + on_tick => sub { + my ($timer) = @_; + if ( $process->is_running ) { + my $resp = get("$url/__lbheartbeat__"); + if ($resp && $resp =~ /^httpd OK$/) { + $timer->stop; + $is_running_f->done($resp); + } + say "httpd doesn't seem to be up at $url. waiting..."; + } + elsif ( $process->is_exited ) { + $timer->stop; + $is_running_f->fail("process exited early"); + } + elsif ( $ticks++ > 60 ) { + $timer->stop; + $is_running_f->fail("is_running_future() timeout after $ticks seconds"); + } + $timer->stop if $ticks++ > 60; + }, + ); + $loop->add($run_checker->start); + return $is_running_f->get(); +} sub copy_qa_extension { say "copying the QA extension..."; @@ -93,8 +225,6 @@ sub copy_qa_extension { } sub wait_for_db { - die "/app/localconfig is missing\n" unless -f "/app/localconfig"; - my $c = Bugzilla::Install::Localconfig::read_localconfig(); for my $var (qw(db_name db_host db_user db_pass)) { die "$var is not set!" unless $c->{$var}; @@ -117,20 +247,29 @@ sub wait_for_db { die "unable to connect to $dsn as $c->{db_user}\n" unless $dbh; } -sub wait_for_httpd { - my ($url) = @_; - my $ok = 0; - foreach (1..12) { - say 'checking if httpd is up...' if $_ > 1; - my $resp = get("$url/__lbheartbeat__"); - if ($resp && $resp =~ /^httpd OK$/) { - $ok = 1; - last; +sub on_exception { + my ($name, $f) = @_; + return sub { + my ( $self, $exception, $errno, $exitcode ) = @_; + + if ( length $exception ) { + $f->fail("$name died with the exception $exception " . "(errno was $errno)\n"); } - say "httpd doesn't seem to be up at $url. waiting..."; - sleep(10); - } - die "unable to connect to httpd at $url\n" unless $ok; + elsif ( ( my $status = WEXITSTATUS($exitcode) ) == 255 ) { + $f->fail("$name failed to exec() - $errno\n"); + } + else { + $f->fail("$name exited with exit status $status\n"); + } + }; +} + +sub on_finish { + my ($f) = @_; + return sub { + my ($self, $exitcode) = @_; + $f->done(WEXITSTATUS($exitcode)); + }; } sub localconfig_from_env { @@ -165,6 +304,8 @@ sub write_localconfig { my $filename = "/app/localconfig"; + die "/app/localconfig already exists!" if -f $filename; + foreach my $var (Bugzilla::Install::Localconfig::LOCALCONFIG_VARS) { my $name = $var->{name}; my $value = $localconfig->{$name}; @@ -174,8 +315,6 @@ sub write_localconfig { } } - unlink($filename); - # Ensure output is sorted and deterministic local $Data::Dumper::Sortkeys = 1; -- cgit v1.2.3-24-g4f1b