Alien-Xrepo
view release on metacpan or search on metacpan
t/051_engine.t view on Meta::CPAN
};
subtest 'probe marks satisfied packages and install skips them' => sub {
my $spy = Alien::Xrepo::Build::TestSpy->new( preinstalled => { zstd => '1.5.6' } );
my $b = build( [ { name => 'zstd', version => '1.5.6' }, 'libsdl3' ], repo => $spy, );
$b->run;
my %by_action = map { $_->{action} => 1 } @{ $spy->calls };
ok $by_action{info}, 'probe asked xrepo for each package';
is $b->install_prop->{probed}{zstd}{satisfied}, 1, 'matching version satisfied';
is $b->install_prop->{probed}{libsdl3}{satisfied}, 0, 'no store hit for libsdl3';
my (@installs) = grep { $_->{action} eq 'install' } @{ $spy->calls };
is scalar @installs, 1, 'only the unsatisfied package was installed';
is $installs[0]{name}, 'libsdl3', 'skip hit the right package';
is $b->install_type, 'share', 'a fetched package flips install_type';
};
subtest 'probe_policy always reinstalls despite a hit' => sub {
my $spy = Alien::Xrepo::Build::TestSpy->new( preinstalled => { zstd => '1.5.6' } );
my $b = build( ['zstd'], repo => $spy, probe_policy => 'always' );
$b->run;
my (@installs) = grep { $_->{action} eq 'install' } @{ $spy->calls };
is scalar @installs, 1, 'always policy installed anyway';
};
subtest 'probe_policy off never probes' => sub {
my $spy = Alien::Xrepo::Build::TestSpy->new;
my $b = build( ['zstd'], repo => $spy, probe_policy => 'off' );
$b->run;
my (@infos) = grep { $_->{action} eq 'info' } @{ $spy->calls };
is scalar @infos, 0, 'no probe calls with policy off';
ok !$b->install_prop->{probed}{zstd}, 'no probe data recorded';
};
subtest 'a failed package isolates: siblings install, error recorded' => sub {
my $spy = Alien::Xrepo::Build::TestSpy->new( fail => { libsdl3 => 1 } );
my $b = build( [ 'zstd', { name => 'libsdl3' }, 'ninja' ], repo => $spy, probe_policy => 'off' );
$b->run;
my (@installs) = grep { $_->{action} eq 'install' } @{ $spy->calls };
is scalar @installs, 3, 'all packages attempted';
like $b->runtime_prop->{errors}{libsdl3}, qr/boom/, 'failure captured in runtime_prop';
ok exists $b->runtime_prop->{packages}{zstd}, 'sibling before the failure installed';
ok exists $b->runtime_prop->{packages}{ninja}, 'sibling after the failure installed';
is $b->install_type, 'share', 'a partial success is still a share install';
};
subtest 'gather fetches anything the install did not produce' => sub {
my $spy = Alien::Xrepo::Build::TestSpy->new;
my $b = build( ['zstd'], repo => $spy, probe_policy => 'off' );
$b->install;
$b->gather;
my (@fetches) = grep { $_->{action} eq 'fetch' } @{ $spy->calls };
is scalar @fetches, 0, 'gather skips packages already gathered by install';
is $b->runtime_prop->{packages}{zstd}{version}, '1.2.3', 'runtime data present';
my $spy2 = Alien::Xrepo::Build::TestSpy->new;
my $b2 = build( ['zstd'], repo => $spy2, probe_policy => 'off' );
$b2->gather;
my (@f2) = grep { $_->{action} eq 'fetch' } @{ $spy2->calls };
is scalar @f2, 1, 'gather fetches when install never ran';
};
subtest 'export writes the runtime snapshot' => sub {
my $snap = path($dir)->child('snapshot.json');
my $spy = Alien::Xrepo::Build::TestSpy->new;
my $b = build( [ { name => 'zstd', version => '1.5.6' } ], repo => $spy, probe_policy => 'off', snapshot => $snap );
$b->run;
ok -e $snap, 'snapshot file written';
my $data = decode_json( $snap->slurp_utf8 );
is $data->{install_type}, 'share', 'snapshot records install_type';
is $data->{packages}{zstd}{version}, '1.5.6', 'snapshot records runtime data';
is $data->{packages}{zstd}{installdir}, '/tmp/store/zstd', 'snapshot records installdir';
};
subtest 'checkpoint/resume skips completed work' => sub {
my $cp = path($dir)->child('state.json');
my $spy = Alien::Xrepo::Build::TestSpy->new;
my $b = build( ['zstd'], repo => $spy, probe_policy => 'off', checkpoint => $cp );
$b->run;
my $calls_after_first = scalar @{ $spy->calls };
ok $calls_after_first > 0, 'first run made calls';
ok -e $cp, 'checkpoint file written';
my $spy2 = Alien::Xrepo::Build::TestSpy->new;
my $b2 = build( ['zstd'], repo => $spy2, probe_policy => 'off', checkpoint => $cp, resume => 1 );
my @installs2 = grep { $_->{action} eq 'install' } @{ $spy2->calls };
is scalar @installs2, 0, 'resume did not reinstall';
is $b2->install_type, 'share', 'resumed build kept prior install_type';
is $b2->runtime_prop->{packages}{zstd}{version}, '1.2.3', 'resumed build kept runtime data';
is $b2->stage_done->{install}, 1, 'resumed build knows install completed';
};
subtest 'hooks run for every registered stage' => sub {
my $spy = Alien::Xrepo::Build::TestSpy->new;
my $b = build( ['zstd'], repo => $spy, probe_policy => 'off' );
my @ran;
for my $stage (qw[install gather]) {
$b->register_hook( $stage => sub { push @ran, $stage } );
}
ok $b->has_hook('install'), 'register_hook/has_hook agree';
ok !$b->has_hook('probe'), 'unregistered stage has no hooks';
like dies {
$b->register_hook( bogus => sub { } )
}, qr/Unknown stage/, 'bad stage dies';
$b->run;
is \@ran, [qw[install gather]], 'hooks fired in stage order';
};
our @HOOK_RAN;
subtest 'recipe hooks load once and register stage callbacks' => sub {
my $hdir = Path::Tiny->tempdir;
$hdir->child('RecipeHooksDemo.pm')->spew_utf8(
q{
package RecipeHooksDemo;
sub register_hooks {
my ($build) = @_;
push @main::HOOK_RAN, 'register';
$build->register_hook( install => sub { push @main::HOOK_RAN, 'install' } );
}
1;
}
);
local @INC = ( @INC, $hdir->stringify );
my $spy = Alien::Xrepo::Build::TestSpy->new;
my $b = build( ['zstd'], repo => $spy, probe_policy => 'off', recipe_extra => { hooks => ['RecipeHooksDemo'] } );
is \@main::HOOK_RAN, [], 'nothing registered before configure';
$b->configure;
is \@main::HOOK_RAN, ['register'], 'recipe hook module saw register_hooks';
is $b->has_hook('install'), 1, 'recipe hook attached a stage hook';
@main::HOOK_RAN = ();
$b->configure;
is scalar @main::HOOK_RAN, 0, 'recipe hooks load once even if configure repeats';
$b->install;
is \@main::HOOK_RAN, ['install'], 'recipe-registered hook fired at its stage';
};
subtest 'recipe hooks die clearly when the module lacks register_hooks' => sub {
my $hdir = Path::Tiny->tempdir;
$hdir->child('RecipeHooksBad.pm')->spew_utf8("package RecipeHooksBad;\n1;\n");
local @INC = ( @INC, $hdir->stringify );
my $spy = Alien::Xrepo::Build::TestSpy->new;
my $b = build( ['zstd'], repo => $spy, recipe_extra => { hooks => ['RecipeHooksBad'] } );
like dies { $b->configure }, qr/register_hooks/, 'missing register_hooks dies at configure';
};
subtest 'pkg_roots resolve a package from a system root' => sub {
my $root = Path::Tiny->tempdir;
$root->child('include')->mkpath;
$root->child('lib')->mkpath;
$root->child( 'include', 'zstd.h' )->spew_utf8('#define ZSTD 1');
$root->child( 'lib', 'libzstd.a' )->spew_utf8('');
local $ENV{ZSTD_ROOT} = $root->stringify;
my $spy = Alien::Xrepo::Build::TestSpy->new;
my $b = build( ['zstd'], repo => $spy, recipe_extra => { pkg_roots => { zstd => 'ZSTD_ROOT' } } );
$b->run;
my (@infos) = grep { $_->{action} eq 'info' } @{ $spy->calls };
my (@installs) = grep { $_->{action} eq 'install' } @{ $spy->calls };
my (@fetches) = grep { $_->{action} eq 'fetch' } @{ $spy->calls };
is scalar @infos, 0, 'probe never consults xrepo for a root-resolved package';
is scalar @installs, 0, 'install never consults xrepo for a root-resolved package';
is scalar @fetches, 0, 'gather never consults xrepo for a root-resolved package';
is $b->install_prop->{probed}{zstd}{satisfied}, 1, 'probe reports the root-satisfied package';
is $b->install_prop->{probed}{zstd}{root}, $root->stringify, 'probe records the root';
is $b->runtime_prop->{packages}{zstd}{installdir}, $root->stringify, 'package data points at the root';
is $b->runtime_prop->{packages}{zstd}{includedirs}[0], $root->child('include')->stringify, 'include dir from the root';
is $b->runtime_prop->{packages}{zstd}{linkdirs}[0], $root->child('lib')->stringify, 'lib dir from the root';
is $b->runtime_prop->{packages}{zstd}{kind}, 'system', 'root entry marked as system-provided';
is $b->install_type, 'system', 'a root-resolved package leaves install_type at system';
ok !exists $b->runtime_prop->{errors}{zstd}, 'no error recorded';
};
subtest 'pkg_roots ignore a variable that does not name a directory' => sub {
local $ENV{ZSTD_ROOT} = 'C:/definitely/not/a/real/zstd/root';
my $spy = Alien::Xrepo::Build::TestSpy->new;
my $b = build( ['zstd'], repo => $spy, recipe_extra => { pkg_roots => { zstd => 'ZSTD_ROOT' } } );
$b->run;
my (@infos) = grep { $_->{action} eq 'info' } @{ $spy->calls };
is scalar @infos, 1, 'probe consulted xrepo when the root env var was unusable';
is $b->install_prop->{probed}{zstd}{satisfied}, 0, 'package not satisfied by a dead root';
ok exists $b->runtime_prop->{packages}{zstd}, 'package installed via xrepo as normal';
};
done_testing;
( run in 0.623 second using v1.01-cache-2.11-cpan-364913b4093 )