2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-04 12:07:56 +00:00
Files
xcat-core/xCAT-test/unit/command_utils.t
T
2026-09-02 22:58:22 -03:00

216 lines
6.3 KiB
Perl

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();