summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/entrypoint.pl227
1 files changed, 183 insertions, 44 deletions
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;