Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions lib/App/Yath2/Command/test.pm
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ use Object::HashBase qw{
<plugins
};

use Cwd ();
use File::Path qw/remove_tree/;
use File::Spec();
use POSIX qw/strftime/;
use Time::HiRes qw/sleep/;

use App::Yath2 ();
use Test2::Harness2();
use Test2::Harness2::TestFile();
use Test2::Harness2::Resource::JobCount();
Expand Down Expand Up @@ -111,6 +113,50 @@ sub run {

die "No test files matched extensions (@ext) under: @$args\n" unless @files;

# Build T2_HARNESS_INCLUDES for test children: app path first, then the
# user's -I paths (settings->tests->includes, already resolved), then the
# default lib/blib directories (on by default, disabled by --no-lib /
# --no-blib). Paths are absolutised relative to the current working
# directory so they remain valid regardless of the RunService's CWD.
#
# We PREPEND to any T2_HARNESS_INCLUDES value already set in the
# environment (e.g. /foo;/bar;/baz from nested_includes.t) so caller-
# injected paths survive but the tester's full @INC dump (added by
# App::Yath2::Tester for its own yath-subprocess setup) ends up after
# our ordered prefix.
{
my $cwd = Cwd::getcwd();
my @new_inc;

push @new_inc, App::Yath2->app_path;

if (eval { $settings->can('check_group') && $settings->check_group('tests') }) {
my $ts = $settings->tests;
for my $path (@{$ts->includes // []}) {
push @new_inc, File::Spec->rel2abs($path, $cwd);
}
unless (defined($ts->lib) && !$ts->lib) {
push @new_inc, File::Spec->catdir($cwd, 'lib');
}
unless (defined($ts->blib) && !$ts->blib) {
push @new_inc, File::Spec->catdir($cwd, 'blib', 'lib');
push @new_inc, File::Spec->catdir($cwd, 'blib', 'arch');
}
}

my %seen;
my @all_inc;
for my $p (@new_inc) {
push @all_inc, $p unless $seen{$p}++;
}
if (my $existing = $ENV{T2_HARNESS_INCLUDES}) {
for my $p (grep { length && $_ ne '.' } split /;/, $existing) {
push @all_inc, $p unless $seen{$p}++;
}
}
$ENV{T2_HARNESS_INCLUDES} = join ';', @all_inc;
}

my $workdir = $settings->workspace->workdir;

my $spawn = Test2::Harness2->spawn(
Expand Down
50 changes: 41 additions & 9 deletions lib/Test2/Harness2/RunService.pm
Original file line number Diff line number Diff line change
Expand Up @@ -189,21 +189,55 @@ sub request_handler_launch_job {
return {ok => 0, error => "'test_file' must be absolute"}
unless $test_file_abs =~ m{^/};

# Parse the test file to detect non-perl scripts (shell scripts, etc.)
# via their shebang line. We need this before building the launch command
# so we can decide whether to use -I flags or PERL5LIB.
require Test2::Harness2::TestFile;
my $test_file_spec = Test2::Harness2::TestFile->new(file => $test_file_abs);
$test_file_spec->scan;

# The harness's synthetic-skip / synthetic-fail paths hand us an
# explicit launch command (perl -e '...'). Default to running the
# real test file when no override is present. When the launch
# payload's env carries T2_HARNESS_INCLUDES (forwarded by
# Test2::Harness2::_launch_job), turn it into -I flags so the
# child's @INC actually picks the paths up -- the env var alone
# is not enough since exec(perl ...) starts a fresh interpreter.
# real test file when no override is present.
#
# T2_HARNESS_INCLUDES (forwarded by Test2::Harness2::_launch_job and
# populated by Command::test from the user's -I/--lib/--blib options)
# carries the correct include paths for test children. We convert these
# to -I flags for perl scripts, or to PERL5LIB for non-perl scripts
# (shell wrappers that re-exec perl).
my %extra_env;
if (!defined $launch_cmd) {
my @extra_inc;
if (my $payload_env = $payload->{env}) {
my $inc = $payload_env->{T2_HARNESS_INCLUDES};
@extra_inc = grep { length && $_ ne '.' } split /;/, $inc
if defined $inc && length $inc;
}
$launch_cmd = [$^X, (map { "-I$_" } @extra_inc), '-Ilib', $test_file_abs];

if ($test_file_spec->non_perl) {
# Non-perl scripts (e.g. shell wrappers that exec perl): pass
# include paths via PERL5LIB so the re-execed perl sees them.
# Do not use -I flags — they would be forwarded by perl to the
# shebang interpreter (e.g. bash), which does not understand them.
# Always include 'lib' so harness internals (e.g. Stream2
# formatter) are reachable even when T2_HARNESS_INCLUDES is unset.
my $sep = $^O eq 'MSWin32' ? ';' : ':';
my $new_perl5lib = join $sep, @extra_inc, 'lib';
if (my $existing = $ENV{PERL5LIB}) {
$new_perl5lib .= "$sep$existing";
}
$extra_env{PERL5LIB} = $new_perl5lib;
# Run the script directly; the OS kernel handles the shebang.
$launch_cmd = [$test_file_abs];
}
else {
# Perl scripts: inject include paths as -I flags on the command
# line. This sets @INC before any module is loaded, which is
# required because exec() starts a fresh interpreter.
# Always include -Ilib so harness internals (e.g. Stream2
# formatter) are reachable even when T2_HARNESS_INCLUDES is unset.
$launch_cmd = [$^X, (map { "-I$_" } @extra_inc), '-Ilib', $test_file_abs];
}
}

# Default the payload-level log_file only if the caller wants one;
Expand All @@ -218,8 +252,6 @@ sub request_handler_launch_job {
# test_file path so the resulting .json includes the relative
# and absolute test-file paths. Callers that supply their own
# spec are left alone.
require Test2::Harness2::TestFile;
my $test_file_spec = Test2::Harness2::TestFile->new(file => $test_file_abs);

my @logger_specs = map { _maybe_inject_test_file_spec($_, $test_file_spec) } @$payload_loggers;

Expand All @@ -230,7 +262,7 @@ sub request_handler_launch_job {
launch => $launch_cmd,
new_pgroup => 1,
parent_pids => [$$],
env_vars => {T2_FORMATTER => 'Stream2', %$env},
env_vars => {T2_FORMATTER => 'Stream2', %$env, %extra_env},
logdir => $self->{+LOGDIR},
run_id => $run_id,
job_id => $job_id,
Expand Down
2 changes: 1 addition & 1 deletion t/Yath/integration/concurrency.t
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# HARNESS-CONFLICTS YATH
use Test2::V0;
plan skip_all => "TODO: job concurrency scheduling not validated yet against current scheduler";
plan skip_all => "TODO: test uses \$log->poll() (JSONL API) but log=>1 now returns a workdir; needs rewrite to use App::Yath2::LogArchive for job event ordering assertions";
__END__

use Test2::V0;
Expand Down
4 changes: 0 additions & 4 deletions t/Yath/integration/includes.t
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
# HARNESS-CONFLICTS YATH
use Test2::V0;
plan skip_all => "TODO: -I/--unsafe-inc include handling not aligned with current command::test";
__END__

use Test2::V0;
use IPC::Cmd qw/can_run/;

Expand Down
2 changes: 1 addition & 1 deletion t/Yath/integration/projects.t
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# HARNESS-CONFLICTS YATH
use Test2::V0;
plan skip_all => "TODO: projects command output not aligned with current renderer";
plan skip_all => "TODO: App::Yath2::Command::projects needs run() override — inherits test's guard that requires explicit args, no CWD fallback";
__END__

use Test2::V0;
Expand Down
4 changes: 0 additions & 4 deletions t/Yath/integration/signals.t
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
# HARNESS-CONFLICTS YATH
use Test2::V0;
plan skip_all => "TODO: signal handling under nested yath not aligned with current Streamer (AUTHOR_TESTING bypasses old gate)";
__END__

use Test2::V0;
use Test2::Require::AuthorTesting;

Expand Down
2 changes: 1 addition & 1 deletion t/Yath/integration/smoke.t
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# HARNESS-CONFLICTS YATH
use Test2::V0;
plan skip_all => "TODO: plugin loading (-p+SmokePlugin) and -D dev-libs not aligned";
plan skip_all => "TODO: test uses \$log->poll() (JSONL API) but log=>1 now returns a workdir; needs rewrite to use App::Yath2::LogArchive for event iteration";
__END__

use Test2::V0;
Expand Down
2 changes: 1 addition & 1 deletion t/Yath/integration/stamps.t
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# HARNESS-CONFLICTS YATH
use Test2::V0;
plan skip_all => "TODO: plugin loading and event timestamp rendering not aligned";
plan skip_all => "TODO: test uses \$log->poll() (JSONL API) but log=>1 now returns a workdir; needs rewrite to App::Yath2::LogArchive; also --no-plugins flag not yet implemented";
__END__

use Test2::V0;
Expand Down
Loading