2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-04 12:07:56 +00:00

test(utils): reuse and cover executable lookup

This commit is contained in:
Vinícius Ferrão
2026-08-24 20:03:05 -03:00
parent 77c1694b03
commit 0c0803d83a
12 changed files with 282 additions and 37 deletions
@@ -5,7 +5,7 @@ cmd:mkdir -p /tmp/xcatprobe_l
cmd:xcatprobe -l
check:rc==0
check:output=~Supported sub commands are:
cmd:for module in GlobalDef.pm NetworkUtils.pm ServiceNodeUtils.pm; do test -r "/opt/xcat/probe/lib/perl/xCAT/$module" || exit 1; done
cmd:for module in CommandUtils.pm GlobalDef.pm NetworkUtils.pm ServiceNodeUtils.pm; do test -r "/opt/xcat/probe/lib/perl/xCAT/$module" || exit 1; done
check:rc==0
cmd:xcatprobe -l|grep -v "Supported sub commands are" |awk '/^[[:graph:]]/ {print $1}'|sort > /tmp/xcatprobe_l/subcmd_from_xcatprobe_l
cmd:ls -l /opt/xcat/probe/subcmds/ |awk '/^-/ {print $9}'|sort > /tmp/xcatprobe_l/subcmd_under_subcmds_dir
@@ -8,9 +8,10 @@ use File::Temp qw/tempfile/;
use JSON ();
use Test::More;
use xCAT::CommandUtils;
use xCAT::DHCP::Backend::Kea;
my $kea_dhcp4 = command_path('kea-dhcp4');
my $kea_dhcp4 = xCAT::CommandUtils::find_executable('kea-dhcp4');
plan skip_all => 'kea-dhcp4 is not installed' unless $kea_dhcp4;
my $validation_dir = validation_temp_dir($kea_dhcp4);
@@ -106,7 +107,7 @@ ok( !$result->{error}, 'generated Kea DHCPv4 config validates with kea-dhcp4 -t'
unlink $path;
SKIP: {
skip 'kea-dhcp6 is not installed', 1 unless command_path('kea-dhcp6');
skip 'kea-dhcp6 is not installed', 1 unless xCAT::CommandUtils::find_executable('kea-dhcp6');
my $dhcp6_json = $backend->render_dhcp6_config(
{
interfaces => ['*'],
@@ -150,7 +151,7 @@ SKIP: {
}
SKIP: {
skip 'kea-dhcp-ddns is not installed', 1 unless command_path('kea-dhcp-ddns');
skip 'kea-dhcp-ddns is not installed', 1 unless xCAT::CommandUtils::find_executable('kea-dhcp-ddns');
my $ddns_json = $backend->render_ddns_config(
{
'tsig-keys' => [
@@ -180,7 +181,7 @@ SKIP: {
}
SKIP: {
skip 'kea-ctrl-agent is not installed', 1 unless command_path('kea-ctrl-agent');
skip 'kea-ctrl-agent is not installed', 1 unless xCAT::CommandUtils::find_executable('kea-ctrl-agent');
my $ctrl_agent_json = $backend->render_ctrl_agent_config(
{
dhcp6 => 1,
@@ -195,21 +196,6 @@ SKIP: {
}
done_testing();
sub command_path {
my ($command) = @_;
foreach my $dir ( split /:/, $ENV{PATH} || '' ) {
next unless $dir;
return "$dir/$command" if -x "$dir/$command";
}
foreach my $path ( "/usr/sbin/$command", "/usr/bin/$command", "/sbin/$command", "/bin/$command" ) {
return $path if -x $path;
}
return;
}
sub validation_temp_dir {
my ($kea_dhcp4) = @_;
@@ -11,14 +11,15 @@ use POSIX qw/WNOHANG _exit setgid setuid/;
use Test::More;
use Time::HiRes qw/sleep time/;
use xCAT::CommandUtils;
use xCAT::DHCP::Backend::Kea;
plan skip_all => 'set XCAT_KEA_LIVE_SMOKE=1 to run live Kea daemon smoke test'
unless $ENV{XCAT_KEA_LIVE_SMOKE};
plan skip_all => 'live Kea daemon smoke test must run as root' unless $> == 0;
my $kea_dhcp4 = command_path('kea-dhcp4');
my $kea_ctrl = command_path('kea-ctrl-agent');
my $kea_dhcp4 = xCAT::CommandUtils::find_executable('kea-dhcp4');
my $kea_ctrl = xCAT::CommandUtils::find_executable('kea-ctrl-agent');
plan skip_all => 'kea-dhcp4 and kea-ctrl-agent are required'
unless $kea_dhcp4 && $kea_ctrl;
@@ -192,21 +193,6 @@ SKIP: {
stop_daemons(\%children);
done_testing();
sub command_path {
my ($command) = @_;
foreach my $dir ( split /:/, $ENV{PATH} || '' ) {
next unless $dir;
return "$dir/$command" if -x "$dir/$command";
}
foreach my $path ( "/usr/sbin/$command", "/usr/bin/$command", "/sbin/$command", "/bin/$command" ) {
return $path if -x $path;
}
return;
}
sub start_daemon {
my ( $account, $command, $log, @args ) = @_;
my $pid = fork();
+215
View File
@@ -0,0 +1,215 @@
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../../perl-xCAT";
use Cwd qw/getcwd/;
use File::Path qw/make_path/;
use File::Temp qw/tempdir/;
use Test::More;
use xCAT::CommandUtils;
my $command_utils_source = "$FindBin::Bin/../../perl-xCAT/xCAT/CommandUtils.pm";
open( my $source_fh, '<', $command_utils_source )
or die "Unable to read $command_utils_source: $!";
my $source = do { local $/; <$source_fh> };
close($source_fh) or die "Unable to close $command_utils_source: $!";
like(
$source,
qr/my \@SYSTEM_FALLBACK_DIRS = qw\(\s*\/usr\/sbin\s*\/usr\/bin\s*\/sbin\s*\/bin\s*\);/s,
'the built-in system fallback order matches the replaced callers'
);
my $root = tempdir(CLEANUP => 1);
my $first_dir = "$root/first";
my $second_dir = "$root/second";
my $fallback_dir = "$root/fallback";
make_path( $first_dir, $second_dir, $fallback_dir, "$root/relative" );
sub write_executable {
my ($path) = @_;
open( my $fh, '>', $path ) or die "Unable to write $path: $!";
print {$fh} "#!/bin/sh\nexit 0\n";
close($fh) or die "Unable to close $path: $!";
chmod 0755, $path or die "Unable to make $path executable: $!";
return $path;
}
my $first_tool = write_executable("$first_dir/xcat-command-utils-tool");
my $second_tool = write_executable("$second_dir/xcat-command-utils-tool");
is(
xCAT::CommandUtils::find_executable(
'xcat-command-utils-tool',
path => "$first_dir:$second_dir",
fallback_dirs => [],
),
$first_tool,
'PATH entries are searched in order'
);
chmod 0644, $first_tool or die "Unable to remove execute permission from $first_tool: $!";
is(
xCAT::CommandUtils::find_executable(
'xcat-command-utils-tool',
path => "$first_dir:$second_dir",
fallback_dirs => [],
),
$second_tool,
'non-executable candidates are skipped'
);
{
local $ENV{PATH} = $second_dir;
is(
xCAT::CommandUtils::find_executable('xcat-command-utils-tool'),
$second_tool,
'the process PATH is used by default'
);
is(
xCAT::CommandUtils::find_executable(
'xcat-command-utils-tool',
path => $first_dir,
fallback_dirs => [],
),
undef,
'an explicit path overrides the process PATH'
);
}
my $fallback_tool = write_executable("$fallback_dir/xcat-command-utils-fallback");
is(
xCAT::CommandUtils::find_executable(
'xcat-command-utils-fallback',
path => '',
fallback_dirs => [ '', $fallback_dir ],
),
$fallback_tool,
'custom fallback directories are searched after PATH and ignore empty entries'
);
is(
xCAT::CommandUtils::find_executable(
'xcat-command-utils-fallback',
path => '',
fallback_dirs => [],
),
undef,
'fallback lookup can be disabled'
);
is(
xCAT::CommandUtils::find_executable(
'bin',
path => '',
fallback_dirs => [''],
),
undef,
'empty fallback entries are ignored instead of matching executable root directories'
);
is(
xCAT::CommandUtils::find_executable(
'xcat-command-utils-tool',
path => '',
fallback_dirs => [$first_dir],
),
undef,
'non-executable fallback candidates are skipped'
);
my $fallback_order_first = write_executable("$first_dir/xcat-command-utils-fallback-order");
write_executable("$second_dir/xcat-command-utils-fallback-order");
is(
xCAT::CommandUtils::find_executable(
'xcat-command-utils-fallback-order',
path => '',
fallback_dirs => [ $first_dir, $second_dir ],
),
$fallback_order_first,
'custom fallback directories are searched in order'
);
my $path_collision = write_executable("$second_dir/xcat-command-utils-collision");
write_executable("$fallback_dir/xcat-command-utils-collision");
is(
xCAT::CommandUtils::find_executable(
'xcat-command-utils-collision',
path => $second_dir,
fallback_dirs => [$fallback_dir],
),
$path_collision,
'PATH matches take precedence over fallback matches'
);
my $system_shell = xCAT::CommandUtils::find_executable( 'sh', path => '' );
my ($expected_system_shell) = grep { -x "$_/sh" } qw(/usr/sbin /usr/bin /sbin /bin);
is(
$system_shell,
defined($expected_system_shell) ? "$expected_system_shell/sh" : undef,
'standard system directories are searched by default'
);
my $original_dir = getcwd();
chdir($root) or die "Unable to enter $root: $!";
is(
xCAT::CommandUtils::find_executable(
'bin',
path => ":$second_dir",
fallback_dirs => [],
),
undef,
'empty PATH entries are ignored instead of matching executable root directories'
);
write_executable("$root/relative/xcat-command-utils-relative");
is(
xCAT::CommandUtils::find_executable(
'xcat-command-utils-relative',
path => 'relative',
fallback_dirs => [],
),
'relative/xcat-command-utils-relative',
'relative PATH entries preserve the existing candidate path shape'
);
make_path("$root/0");
write_executable("$root/0/xcat-command-utils-zero-entry");
is(
xCAT::CommandUtils::find_executable(
'xcat-command-utils-zero-entry',
path => "0:$second_dir",
fallback_dirs => [],
),
undef,
'a PATH component named zero retains the existing falsy-entry behavior'
);
chdir($original_dir) or die "Unable to restore $original_dir: $!";
my $marker = "$root/shell-was-invoked";
my $literal_name = 'xcat-command-utils;touch shell-was-invoked';
my $literal_tool = write_executable("$second_dir/$literal_name");
chdir($root) or die "Unable to enter $root for shell-safety lookup: $!";
is(
xCAT::CommandUtils::find_executable(
$literal_name,
path => $second_dir,
fallback_dirs => [],
),
$literal_tool,
'command names are treated as filesystem paths without shell interpretation'
);
ok( !-e $marker, 'executable lookup never invokes a shell' );
chdir($original_dir) or die "Unable to restore $original_dir: $!";
is(
xCAT::CommandUtils::find_executable( undef, path => $second_dir ),
undef,
'an undefined command is not searched'
);
is(
xCAT::CommandUtils::find_executable( '', path => $second_dir ),
undef,
'an empty command is not searched'
);
done_testing();
+8
View File
@@ -307,4 +307,12 @@ is(
'forced Kea succeeds when available'
);
{
local $ENV{PATH} = '';
ok(
xCAT::DHCP::Backend::_command_exists('sh'),
'backend availability retains the standard system-directory fallback'
);
}
done_testing();
+9
View File
@@ -162,6 +162,15 @@ foreach my $case (@sysconfig_policy_cases) {
close($ip_fh);
chmod 0755, $fake_ip;
{
local $ENV{PATH} = $tmpdir;
is(
xCAT_plugin::dhcp::kea_command_path('ip'),
$fake_ip,
'DHCP route command lookup retains the first executable PATH match'
);
}
no warnings 'redefine';
local *xCAT_plugin::dhcp::kea_command_path = sub {
my ($command) = @_;
+9
View File
@@ -580,6 +580,15 @@ FAKE_KEA
close($fake_kea_fh) or die "Unable to close fake Kea command: $!";
chmod 0755, $fake_kea_dhcp4 or die "Unable to make fake Kea command executable: $!";
{
local $ENV{PATH} = $unit_dir;
is(
xCAT::DHCP::Backend::Kea::_command_path('kea-dhcp4-build-report'),
$fake_kea_dhcp4,
'Kea command lookup retains the first executable PATH match'
);
}
my $command_socket_backend = xCAT::DHCP::Backend::Kea->new(kea_dhcp4_command => $fake_kea_dhcp4);
is( $command_socket_backend->control_socket_path('kea4-ctrl-socket'), '/xcat-test-command-run/kea/kea4-ctrl-socket', 'socket path comes from the Kea build-report command' );
+1
View File
@@ -3,6 +3,7 @@ use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../../perl-xCAT";
use lib "$FindBin::Bin/../../xCAT-probe/lib/perl";
use Test::More;
+1
View File
@@ -3,6 +3,7 @@ use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../../perl-xCAT";
use lib "$FindBin::Bin/../../xCAT-probe/lib/perl";
use File::Slurper qw(write_text);
+1
View File
@@ -3,6 +3,7 @@ use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../../perl-xCAT";
use lib "$FindBin::Bin/../../xCAT-probe/lib/perl";
use File::Temp qw(tempdir);
@@ -3,6 +3,7 @@ use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../../perl-xCAT";
use lib "$FindBin::Bin/../../xCAT-probe/lib/perl";
use Test::More;
@@ -49,6 +50,14 @@ ok(probe_utils::_tcp_listener_output_has_port($netstat_output, 80, qr/httpd|apac
ok(!probe_utils::_tcp_listener_output_has_port($netstat_output, 0), 'invalid port is rejected');
ok(!probe_utils::_tcp_listener_output_has_port($netstat_output, 'http'), 'non-numeric port is rejected');
{
local $ENV{PATH} = '';
ok(
!probe_utils::_command_available('sh'),
'probe command discovery retains PATH-only lookup without system fallbacks'
);
}
{
no warnings 'redefine';
my @commands;
@@ -9,11 +9,14 @@ use File::Spec;
use File::Temp qw(tempdir);
use FindBin;
use lib "$FindBin::Bin/../lib";
use lib "$FindBin::Bin/../../build-utils/lib";
use Test::More;
use XCAT::BuildUtils qw(XCAT_PROBE_HELPERS);
use XCAT::Test::File qw(repo_path slurp_repo_file);
my @helpers = qw(
CommandUtils.pm
GlobalDef.pm
NetworkUtils.pm
ServiceNodeUtils.pm
@@ -26,6 +29,9 @@ my @affected_subcommands = qw(
);
my $builder = slurp_repo_file('buildrpms.pl');
my $debian_builder = slurp_repo_file('build-ubunturepo');
my $installed_probe_test =
slurp_repo_file('xCAT-test/autotest/testcase/probe/xcatproble_list');
my $rpm_spec = slurp_repo_file('xCAT-probe/xCAT-probe.spec');
my $debian_control = slurp_repo_file('xCAT-probe/debian/control');
like($builder, qr/sub prepare_xcat_probe_source_tar\b/, 'RPM builder has dedicated xCAT-probe source preparation');
@@ -65,6 +71,20 @@ for my $helper (@helpers) {
my $source = repo_path(File::Spec->catfile('perl-xCAT', 'xCAT', $helper));
ok(-f $source, "$helper source exists");
like($builder, qr/^\s*\Q$helper\E\s*$/m, "RPM builder stages $helper");
ok(
scalar(grep { $_ eq $helper } XCAT_PROBE_HELPERS),
"the shared builder helper list carries $helper"
);
like(
$debian_builder,
qr{cp -f [^\n]*/perl-xCAT/xCAT/\Q$helper\E\s+[^\n]*/lib/perl/xCAT/},
"Debian builder stages $helper"
);
like(
$installed_probe_test,
qr/cmd:for module in [^;]*\b\Q$helper\E\b[^;]*; do test -r/,
"installed probe payload checks $helper"
);
}
my $tmpdir = tempdir(CLEANUP => 1);