| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- #!/usr/bin/env perl
- # spawn() for real: it forks, detaches, and runs a provisioner, which here is
- # a shell script in a sandbox. t/Trog-DataSource-ProvisionedVirt.t mocks it,
- # so this is the one place where its child is run.
- use 5.040;
- use re '/aasx';
- use warnings FATAL => 'all';
- use FindBin::libs;
- use Test::More;
- use File::Temp qw{tempdir};
- use File::Path ();
- use Time::HiRes ();
- our ( $ROOT, $OLDCWD );
- BEGIN {
- require Cwd;
- $OLDCWD = Cwd::getcwd();
- $ROOT = tempdir( 'tcms-spawn-XXXXXX', TMPDIR => 1, CLEANUP => 1 );
- $ENV{HOME} = $ROOT;
- }
- require_ok('Trog::DataSource::ProvisionedVirt') or BAIL_OUT("Can't find SUT");
- END {
- chdir($OLDCWD) if $OLDCWD;
- }
- {
- no warnings qw{once};
- $Trog::DataSource::ProvisionedVirt::log_dir = "$ROOT/logs";
- }
- File::Path::make_path("$ROOT/bin");
- my sub provisioner ( $name, $body ) {
- my $program = "$ROOT/bin/$name";
- open( my $fh, '>', $program ) or die "$program: $!";
- print {$fh} "#!/bin/sh\n$body\n";
- close($fh) or die "$program: $!";
- chmod( 0755, $program ) or die "$program: $!";
- return $program;
- }
- my sub run ( $domain, $program, $credentials ) {
- my ( $ok, $why ) = Trog::DataSource::ProvisionedVirt::spawn( $domain, $credentials, $ROOT, [ $program, $domain ], 'admin' );
- ok( $ok, "a run for $domain starts" ) or diag($why);
- # What the run says once it has stopped, or undef if it has not stopped
- # within ten seconds.
- foreach ( 1 .. 100 ) {
- my $status = Trog::DataSource::ProvisionedVirt::status($domain);
- return $status if $status && $status->{state} ne 'running';
- Time::HiRes::sleep(0.1);
- }
- return;
- }
- # Starman, under which tPSGI runs, ignores SIGPIPE, and its children inherit
- # that. So a write to a provisioner that has gone fails rather than kills.
- local $SIG{PIPE} = 'IGNORE';
- subtest 'a provisioner that reads its credentials and succeeds' => sub {
- my $status = run( 'reads.test.test', provisioner( 'reads', 'cat >/dev/null; exit 0' ), { password => 'hunter2' } );
- is( $status->{state}, 'ok', 'the run is ok' );
- is( $status->{exit}, '0', 'and exited 0' );
- };
- subtest 'a provisioner that fails' => sub {
- my $status = run( 'fails.test.test', provisioner( 'fails', 'cat >/dev/null; exit 3' ), { password => 'hunter2' } );
- is( $status->{state}, 'failed', 'the run failed' );
- is( $status->{exit}, '3', 'with what the provisioner exited' );
- };
- # More than a pipe holds, so the write cannot finish before the provisioner
- # has gone, whichever of the two is first.
- subtest 'a provisioner that never reads its credentials' => sub {
- my $status = run( 'deaf.test.test', provisioner( 'deaf', 'exit 0' ), { password => 'x' x 1_048_576 } );
- is( $status->{state}, 'failed', 'the run failed, although the provisioner exited 0' );
- my $log = Trog::DataSource::ProvisionedVirt::log_for('deaf.test.test') // '';
- like( $log, qr/could[ ]not[ ]write[ ]to[ ]\N*deaf/, 'and the log says that it never got them' );
- };
- done_testing();
|