#!/usr/bin/env perl package App::Prove::Remote::rprove; use strict; use warnings; if( !caller() ) { $ENV{'RPROVE_HOST'} ? exit remote_shim() : exit run(); } sub run { my ( $host, $workdir, $interpreter ) = ( '127.0.0.1', 0, '', '/usr/bin/perl' ); require App::Prove; require Getopt::Long; Getopt::Long::Configure( 'auto_help', 'pass_through' ); Getopt::Long::GetOptions( 'host|h=s' => \$host, 'workdir=s' => \$workdir, 'interpreter=s' => \$interpreter, ); # Set ENV bitz local @ENV{qw{RPROVE_HOST RPROVE_WORK_DIR RPROVE_INTERPRETER}} = ($host, $workdir, $interpreter); my $prove_args = { 'exec' => $0 }; my $prove = App::Prove->new($prove_args); $prove->process_args(@ARGV); $prove->merge(1); # Run prove return $prove->run ? 0 : 1; } sub remote_shim { require Net::OpenSSH; my $host = $ENV{'RPROVE_HOST'} || '127.0.0.1'; my $wd = $ENV{'RPROVE_WORK_DIR'} || ''; my $bin = $ENV{'RPROVE_INTERPRETER'} || '/usr/bin/perl'; my $test = $ARGV[0] || die "No test passed in!"; my $ssh = Net::OpenSSH->new($host); # Print directly to stdout, as this function merges # STDOUT & STDERR and discards STDIN. # Do this to avoid TTY overflow, and because prove expects # to capture output from STDOUT/ERR anyways. my $system_opts = { 'stdout_discard' => 0, 'stderr_discard' => 0, 'stderr_to_stdout' => 1, 'stdin_discard' => 1, }; # Optionally move to the working directory, run the test. my $cd = $wd ? "cd $wd && " : ''; $ssh->system( $system_opts, "${cd}${bin} '$wd/$test'" ); # Net::OpenSSH sets this value correctly for our purposes here. return $?; } 1; __END__ =head1 NAME rprove - Prove wrapper which executes your tests on the remote host =head1 SYNOPSIS rprove [options] [file ...] Options: -help You are reading it! -host Host to connect to. Defaults to 127.0.0.1. -workdir Directory to change to before running test(s). -interpreter Path on remote to test running interpreter. Defaults to /usr/bin/perl =head1 OPTIONS =over 8 =item B<-help> Print a brief help message and exits. =item B<-host> Host to connect to. Defaults to 127.0.0.1 =item B<-wordkir> Directory to execute the test from. Useful to set if the test requires it. =item B<-interpreter> Path to the interpreter to run your tests with. Default is /usr/bin/perl. Useful to set if you have perl in a nonstandard location or non-perl tests to execute that still emit valid TAP. =back =head1 DESCRIPTION B will locally run prove with a --exec argument which is a shim. This (remote_shim mode) will connect to the remote host for the test in question and run it on the host. Why do this? Because sometimes testing certain scenarios is better done on a disposable remote environment instead of on the local environment. If someone has a "smoker" like environment (Jenkins, some other CI) which also runs your tests, this could also be of use from the orchestrator's end. Anyways, the user is responsible for ensuring the test (and code under test) has been properly deployed to the remote system under test, so make sure that's done first if you want this approach to work. Output of the script is then read by the TAP parser as is expected for a seamless testing experience *as if you had ran the test locally*. =cut