From aebc350e1a87d5dfaa7c8abb1a06cc8ce4e8656b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Thu, 8 Oct 2026 22:40:49 -0300 Subject: [PATCH] test(probe): exercise the built RPM payload --- .github/workflows/xcat_test.yml | 5 + xCAT-test/lib/XCAT/Test/Package.pm | 26 ++++ xCAT-test/native/probe_package_payload.t | 70 ++++++++++ xCAT-test/unit/xcat_probe_package_payload.t | 139 +------------------- 4 files changed, 106 insertions(+), 134 deletions(-) create mode 100644 xCAT-test/lib/XCAT/Test/Package.pm create mode 100644 xCAT-test/native/probe_package_payload.t diff --git a/.github/workflows/xcat_test.yml b/.github/workflows/xcat_test.yml index b3c25ab77..081224e2c 100644 --- a/.github/workflows/xcat_test.yml +++ b/.github/workflows/xcat_test.yml @@ -16,6 +16,11 @@ jobs: run: sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends --no-install-suggests ucf debconf-utils systemd libxml-simple-perl apache2 curl - name: Test Debian package lifecycle run: prove -v xCAT-test/native/xcatd_debian_lifecycle.t xCAT-test/native/xcatd_restart_callers.t xCAT-test/native/apache_package_lifecycle.t xCAT-test/native/package_upgrade_logging.t + - name: Install package test dependencies + run: sudo apt-get install -y --no-install-recommends cpio + - name: Exercise probe package payloads + if: ${{ !cancelled() }} + run: prove xCAT-test/native/probe_package_payload.t - name: Prepare xCAT syslog directory if: ${{ !cancelled() }} run: sudo install -d -o syslog -g adm -m 0750 /var/log/xcat diff --git a/xCAT-test/lib/XCAT/Test/Package.pm b/xCAT-test/lib/XCAT/Test/Package.pm new file mode 100644 index 000000000..23186bc13 --- /dev/null +++ b/xCAT-test/lib/XCAT/Test/Package.pm @@ -0,0 +1,26 @@ +package XCAT::Test::Package; + +use strict; +use warnings; +use Cwd qw(getcwd); +use Exporter qw(import); +use XCAT::Test::Lifecycle (); + +our @EXPORT_OK = qw(run_in); + +sub run_in { + my ($directory, @command) = @_; + my $previous = getcwd(); + chdir($directory) or die "chdir $directory: $!"; + my ($stdout, $stderr, $status); + my $ok = eval { + ($status, $stdout, $stderr) = XCAT::Test::Lifecycle::command(@command); + 1; + }; + my $error = $@; + chdir($previous) or die "chdir $previous: $!"; + die $error unless $ok; + return ($status, $stdout, $stderr); +} + +1; diff --git a/xCAT-test/native/probe_package_payload.t b/xCAT-test/native/probe_package_payload.t new file mode 100644 index 000000000..88ce4f4c7 --- /dev/null +++ b/xCAT-test/native/probe_package_payload.t @@ -0,0 +1,70 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use File::Path qw(make_path); +use File::Slurper qw(read_binary write_text); +use File::Temp qw(tempdir); +use FindBin; +use lib "$FindBin::Bin/../lib", "$FindBin::Bin/../../build-utils/lib"; +use Test::More; +use XCAT::BuildUtils qw(stage_xcat_probe_sources); +use XCAT::Test::File qw(repo_path slurp_repo_file); +use XCAT::Test::Package qw(run_in); + +plan skip_all => 'requires Linux package tools' unless $^O eq 'linux'; +BAIL_OUT('run package builds as an unprivileged user') unless $>; +my $root = tempdir(CLEANUP => 1); +make_path(map { "$root/$_" } qw(SOURCES BUILD BUILDROOT RPMS SRPMS SPECS home)); +local %ENV = (%ENV, HOME => "$root/home", LC_ALL => 'C'); +delete @ENV{qw(PERL5LIB PERL5OPT PERLLIB XCATROOT XCATCFG)}; +stage_xcat_probe_sources(repo_path('.'), "$root/SOURCES", '9.9.9', 1600000000); +my @helpers = qw(CommandUtils.pm GlobalDef.pm NetworkUtils.pm PacketCapture.pm ServiceNodeUtils.pm); +my @commands = qw(code_template detect_dhcpd discovery osdeploy xcatmn); + +sub command { + my ($directory, @args) = @_; + my ($rc, $out, $err) = run_in($directory, @args); + unless (is($rc, 0, "$args[0] completes")) { + diag($out, $err); + BAIL_OUT("@args failed"); + } + return $out; +} + +command($root, 'rpmbuild', '-bb', '--define', "_topdir $root", + '--define', 'version 9.9.9', '--define', 'release 1', repo_path('xCAT-probe/xCAT-probe.spec')); +my @rpms = glob("$root/RPMS/noarch/xCAT-probe-*.rpm"); +is(scalar(@rpms), 1, 'build produces one probe RPM') or BAIL_OUT('missing probe RPM'); +my $requires = command($root, 'rpm', '-qp', '--requires', $rpms[0]); +like($requires, qr/^iproute$/m, 'RPM requires the Linux socket tool provider'); +make_path("$root/rpm"); +command($root, 'bash', '-o', 'pipefail', '-c', + 'cd "$1" && rpm2cpio "$2" | cpio -idm --quiet', 'bash', "$root/rpm", $rpms[0]); +check_payload("$root/rpm", 'RPM'); + +sub check_payload { + my ($destination, $label) = @_; + my $prefix = "$destination/opt/xcat"; + my $helper_dir = "$prefix/probe/lib/perl/xCAT"; + ok(-x $helper_dir, "$label helper directory is searchable") + or BAIL_OUT(sprintf('%s has mode %04o', $helper_dir, (stat($helper_dir))[2] & 0777)); + for my $helper (@helpers) { + my $path = "$prefix/probe/lib/perl/xCAT/$helper"; + ok(-f $path, "$label carries $helper") or BAIL_OUT("missing $path"); + is(read_binary($path), slurp_repo_file("perl-xCAT/xCAT/$helper"), + "$label carries the canonical $helper bytes"); + is((stat($path))[2] & 0777, 0644, "$label helper is readable without execute permission"); + } + write_text("$prefix/bin/xcatclient", "#!/bin/sh\nprintf '[ok]:fixture client\\n'\n"); + chmod 0755, "$prefix/bin/xcatclient" or die $!; + local $ENV{XCATROOT} = $prefix; + local $ENV{PATH} = "$prefix/bin:$ENV{PATH}"; + for my $name (@commands) { + my $out = command($root, "$prefix/probe/subcmds/$name", '-T'); + like($out, qr/^\[ok\]\s*:/m, "$label $name self-test is ready"); + } + my $list = command($root, "$prefix/bin/xcatprobe", '-l'); + like($list, qr/^\Q$_\E\s/m, "$label lists $_") for @commands; +} + +done_testing(); diff --git a/xCAT-test/unit/xcat_probe_package_payload.t b/xCAT-test/unit/xcat_probe_package_payload.t index e690b8740..bac1f371b 100644 --- a/xCAT-test/unit/xcat_probe_package_payload.t +++ b/xCAT-test/unit/xcat_probe_package_payload.t @@ -1,143 +1,14 @@ #!/usr/bin/env perl use strict; use warnings; - -use File::Copy qw(copy); -use File::Path qw(make_path); -use File::Slurper qw(write_text); -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::Test::File qw(slurp_repo_file); -use XCAT::BuildUtils qw(XCAT_PROBE_HELPERS stage_probe_helpers); -use XCAT::Test::File qw(repo_path slurp_repo_file); - -my @helpers = qw( - CommandUtils.pm - GlobalDef.pm - NetworkUtils.pm - PacketCapture.pm - ServiceNodeUtils.pm -); -my @affected_subcommands = qw( - code_template - detect_dhcpd - discovery - osdeploy - xcatmn -); - -# How buildrpms.pl stages the xCAT-probe sources is asserted by -# xcat_probe_sources_staged.t, which runs the staging and reads the archive. Seven assertions -# here matched the text of buildrpms.pl instead, and four of them could not fail: three matched -# the xCAT-release routine, which stages the same way, and one spanned the rest of the file. All -# seven stayed green while the staging directory was unset and every RPM target died. -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( - $rpm_spec, - qr/%if 0%\{\?suse_version\}\s+Requires: iproute2\s+%else\s+Requires: iproute\s+%endif/s, - 'RPM package requires the distro-specific provider of ss' -); -like( - $debian_control, - qr/^Depends:.*\biproute2\s*\|\s*net-tools\b/m, - 'Debian package requires ss or the legacy netstat provider' -); - -# The Debian builder stages the helpers by calling stage_probe_helpers, so run it and -# look at what it produced. The predecessor matched a `cp -f` line in build-ubunturepo, -# which passed whenever that text was reformatted and failed whenever it moved. -my $staged_probe_dir = File::Spec->catdir(tempdir(CLEANUP => 1), 'lib', 'perl', 'xCAT'); -stage_probe_helpers(repo_path(File::Spec->catdir('perl-xCAT', 'xCAT')), $staged_probe_dir); - -for my $helper (@helpers) { - my $source = repo_path(File::Spec->catfile('perl-xCAT', 'xCAT', $helper)); - ok(-f $source, "$helper source exists"); - ok( - scalar(grep { $_ eq $helper } XCAT_PROBE_HELPERS), - "the shared builder helper list carries $helper" - ); - ok( - -f File::Spec->catfile($staged_probe_dir, $helper), - "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); -my $xcatroot = File::Spec->catdir($tmpdir, 'opt', 'xcat'); -my $probe_root = File::Spec->catdir($xcatroot, 'probe'); -my $bin_dir = File::Spec->catdir($xcatroot, 'bin'); -my $subcmd_dir = File::Spec->catdir($probe_root, 'subcmds'); -my $helper_dir = File::Spec->catdir($probe_root, 'lib', 'perl', 'xCAT'); - -make_path($probe_root, $bin_dir); -copy_tree(repo_path(File::Spec->catdir('xCAT-probe', 'lib')), File::Spec->catdir($probe_root, 'lib')); -copy_tree(repo_path(File::Spec->catdir('xCAT-probe', 'subcmds')), $subcmd_dir); - -my $xcatprobe_source = repo_path(File::Spec->catfile('xCAT-probe', 'xcatprobe')); -my $xcatprobe = File::Spec->catfile($bin_dir, 'xcatprobe'); -copy($xcatprobe_source, $xcatprobe) or die "copy $xcatprobe_source: $!"; -chmod 0755, $xcatprobe or die "chmod $xcatprobe: $!"; - -make_path($helper_dir, File::Spec->catdir($subcmd_dir, 'bin')); -for my $helper (@helpers) { - my $source = repo_path(File::Spec->catfile('perl-xCAT', 'xCAT', $helper)); - my $destination = File::Spec->catfile($helper_dir, $helper); - copy($source, $destination) or die "copy $source: $!"; - chmod 0644, $destination or die "chmod $destination: $!"; -} - -my $xcatclient = File::Spec->catfile($bin_dir, 'xcatclient'); -write_text($xcatclient, "#!/bin/sh\nprintf '[ok]:dummy xcatclient\\n'\n"); -chmod 0755, $xcatclient or die "chmod $xcatclient: $!"; - -local $ENV{XCATROOT} = $xcatroot; -local $ENV{PATH} = "$bin_dir:$ENV{PATH}"; -local $ENV{PERL5LIB}; -local $ENV{PERL5OPT}; -local $ENV{PERLLIB}; -delete $ENV{PERL5LIB}; -delete $ENV{PERL5OPT}; -delete $ENV{PERLLIB}; - -for my $subcommand (@affected_subcommands) { - my $command = File::Spec->catfile($subcmd_dir, $subcommand); - my ($rc, $output) = run_command($command, '-T'); - is($rc, 0, "$subcommand self-test exits successfully") or diag($output); - like($output, qr/^\[ok\]\s*:/m, "$subcommand self-test reports ready"); -} - -my ($list_rc, $list_output) = run_command($xcatprobe, '-l'); -is($list_rc, 0, 'xcatprobe list exits successfully') or diag($list_output); -my %listed = map { /^([^\s].*?)\s/ ? ($1 => 1) : () } split /\n/, $list_output; -for my $subcommand (@affected_subcommands) { - ok($listed{$subcommand}, "xcatprobe lists $subcommand") or diag($list_output); -} +my $control = slurp_repo_file('xCAT-probe/debian/control'); +my ($probe) = $control =~ /^Package: xcat-probe\n(.*?)(?:\n\n|\z)/ms; +like($probe // '', qr/^Depends:.*\biproute2\s*\|\s*net-tools\b/m, + 'Debian probe keeps the socket-tool alternatives'); done_testing(); - -sub copy_tree { - my ($source, $destination) = @_; - my $rc = system('cp', '-R', $source, $destination); - is($rc, 0, "copied $source into the package fixture") - or die("unable to create package fixture from $source"); -} - -sub run_command { - my (@command) = @_; - open(my $fh, '-|', @command) or die "run @command: $!"; - my $output = do { local $/; <$fh> }; - close($fh); - return ($? >> 8, $output // ''); -}