mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-10-21 23:28:19 +00:00
Merge pull request #7917 from VersatusHPC/test/r26-package-artifacts
test(packaging): exercise package and repository behavior
This commit is contained in:
@@ -39,6 +39,19 @@ jobs:
|
||||
- name: Run tests
|
||||
if: ${{ !cancelled() }}
|
||||
run: perl github_action_xcat_test.pl
|
||||
- name: Install package test dependencies
|
||||
id: package-deps
|
||||
if: ${{ !cancelled() }}
|
||||
run: sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends --no-install-suggests cpio createrepo-c zstd rsync gnupg libxml-libxml-perl python3-rpm
|
||||
- name: Exercise probe package payloads
|
||||
if: ${{ !cancelled() && steps.package-deps.outcome == 'success' }}
|
||||
run: prove xCAT-test/native/probe_package_payload.t
|
||||
- name: Exercise release repositories
|
||||
if: ${{ !cancelled() && steps.package-deps.outcome == 'success' }}
|
||||
run: prove xCAT-test/native/release_repository.t
|
||||
- name: Check parsed package relations
|
||||
if: ${{ !cancelled() && steps.package-deps.outcome == 'success' }}
|
||||
run: prove xCAT-test/native/package_relations.t
|
||||
rpm_lifecycle_test:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 30
|
||||
|
||||
@@ -32,7 +32,7 @@ Missing prerequisites fail these tests without stopping unrelated test files.
|
||||
Non-Linux hosts report a skip. Set `TMPDIR` to a writable, executable filesystem
|
||||
if the default temporary directory is mounted with `noexec`.
|
||||
|
||||
`go_xcat_os_release.bats` and the full-script cases in
|
||||
`go_xcat_os_release.bats`, `go_xcat_activation.bats` and the full-script cases in
|
||||
`postscripts_apt_get.bats` use the same namespace isolation. They require
|
||||
bats-core 1.4 or newer. OS detection also requires GNU awk for the legacy
|
||||
Red Hat release parser. Postscript cases require GNU diffutils.
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load helpers/script_sandbox
|
||||
|
||||
setup() {
|
||||
setup_script_sandbox awk cat comm cp cut dirname grep head id ln mkdir mktemp mv rm sed sleep sort tr wc xargs
|
||||
mkdir -p "$fixture/etc/yum.repos.d" "$fixture/tools"
|
||||
sandbox+=(--uid 0 --gid 0
|
||||
--ro-bind "$(repo_path xCAT-server/share/xcat/tools/go-xcat)" /run/go-xcat)
|
||||
# An inherited library-only setting must not disable the command.
|
||||
sandbox+=(--setenv GO_XCAT_LIBRARY_ONLY 1)
|
||||
cat >"$fixture/tools/manager" <<'SH'
|
||||
#!/bin/sh
|
||||
operation=
|
||||
for arg do
|
||||
case "$arg" in install|remove) operation=$arg; continue ;; esac
|
||||
[ -n "$operation" ] || continue
|
||||
case "$arg" in -*) continue ;; esac
|
||||
printf '%s %s\n' "$operation" "$arg" >> /run/fixture/transactions
|
||||
done
|
||||
[ "$operation" != install ] || exit 17
|
||||
case "$*" in *repoquery*) printf '%s\n' fixture-package ;; esac
|
||||
exit 0
|
||||
SH
|
||||
cat >"$fixture/tools/rpm" <<'SH'
|
||||
#!/bin/sh
|
||||
case "$*" in
|
||||
'-q --quiet '*) grep -Fxq "$3" /run/fixture/installed ;;
|
||||
*) exit 0 ;;
|
||||
esac
|
||||
SH
|
||||
cat >"$fixture/tools/dpkg-query" <<'SH'
|
||||
#!/bin/sh
|
||||
if grep -Fxq "$3" /run/fixture/installed; then printf 'install ok installed'; else exit 1; fi
|
||||
SH
|
||||
printf '#!/bin/sh\nexit 0\n' >"$fixture/tools/apt-cache"
|
||||
printf '#!/bin/sh\nexit 22\n' >"$fixture/bin/curl"
|
||||
chmod +x "$fixture/bin/curl" "$fixture/tools/"*
|
||||
: >"$fixture/installed"
|
||||
: >"$fixture/transactions"
|
||||
}
|
||||
|
||||
invoke() {
|
||||
local format=$1 architecture=$2 action=$3
|
||||
local debian_arch=$architecture
|
||||
if [ "$format" = rpm ]; then
|
||||
printf 'ID=almalinux\nVERSION_ID=8.10\n' >"$fixture/etc/os-release"
|
||||
cp "$fixture/tools/rpm" "$fixture/bin/rpm"
|
||||
cp "$fixture/tools/manager" "$fixture/bin/dnf"
|
||||
else
|
||||
[ "$architecture" != x86_64 ] || debian_arch=amd64
|
||||
printf '#!/bin/sh\nprintf "%%s\\n" "%s"\n' "$debian_arch" >"$fixture/bin/dpkg"
|
||||
chmod +x "$fixture/bin/dpkg"
|
||||
mkdir -p "$fixture/etc/apt/sources.list.d" "$fixture/var/lib/apt/lists"
|
||||
printf 'ID=ubuntu\nVERSION_ID=24.04\n' >"$fixture/etc/os-release"
|
||||
printf 'DISTRIB_CODENAME=noble\n' >"$fixture/etc/lsb-release"
|
||||
printf 'Package: fixture-package\nVersion: 1\n' >"$fixture/var/lib/apt/lists/test_xcat-core_dists_noble_main_binary-${debian_arch}_Packages"
|
||||
cp "$fixture/var/lib/apt/lists/test_xcat-core_dists_noble_main_binary-${debian_arch}_Packages" "$fixture/var/lib/apt/lists/test_xcat-dep_dists_noble_main_binary-${debian_arch}_Packages"
|
||||
cp "$fixture/tools/dpkg-query" "$fixture/bin/dpkg-query"
|
||||
cp "$fixture/tools/apt-cache" "$fixture/bin/apt-cache"
|
||||
cp "$fixture/tools/manager" "$fixture/bin/apt-get"
|
||||
fi
|
||||
run "${sandbox[@]}" --setenv HOSTTYPE "$architecture" \
|
||||
timeout 30 bash /run/go-xcat -y \
|
||||
--xcat-core=https://packages.example.test/core \
|
||||
--xcat-dep=https://packages.example.test/dep "$action"
|
||||
}
|
||||
|
||||
check_uninstall() {
|
||||
local format=$1 selection=$2 name prefix=xCAT
|
||||
[ "$format" != deb ] || prefix=xcat
|
||||
local architectures=(x86 x86_64 ppc64 ppc64le armv7hf aarch64 riscv64 s390x)
|
||||
[ "$selection" != subset ] || architectures=(ppc64le riscv64)
|
||||
for name in "${architectures[@]}"; do
|
||||
[ "$format" != deb ] || name=${name//_/-}
|
||||
printf '%s-genesis-openembedded-%s\n' "$prefix" "$name"
|
||||
done >"$fixture/installed"
|
||||
printf 'unrelated-package\n' >>"$fixture/installed"
|
||||
invoke "$format" x86_64 uninstall
|
||||
[ "$status" -eq 0 ] || { echo "$output" >&2; return 1; }
|
||||
grep -v '^unrelated-package$' "$fixture/installed" | sed 's/^/remove /' | sort >"$fixture/expected"
|
||||
sort "$fixture/transactions" >"$fixture/actual"
|
||||
diff -u "$fixture/expected" "$fixture/actual"
|
||||
}
|
||||
|
||||
check_install() {
|
||||
local format=$1 architecture=$2 prefix=xCAT legacy=ppc64 x86=x86_64
|
||||
if [ "$format" = deb ]; then prefix=xcat; legacy=ppc64el; x86=amd64; fi
|
||||
invoke "$format" "$architecture" install
|
||||
[ "$status" -eq 17 ] || { echo "$output" >&2; return 1; }
|
||||
local packages=("perl-$prefix" "$prefix-client" "$prefix" "$prefix-buildkit" "$prefix-server"
|
||||
elilo-xcat grub2-xcat ipmitool-xcat syslinux-xcat ipxe-xcat xnba-undi)
|
||||
if [ "$architecture" = riscv64 ]; then
|
||||
packages+=("$prefix-genesis-openembedded-riscv64")
|
||||
else
|
||||
packages+=("$prefix-genesis-scripts-$legacy" "$prefix-genesis-scripts-$x86"
|
||||
"$prefix-genesis-base-$legacy" "$prefix-genesis-base-$x86")
|
||||
fi
|
||||
[ "$format" != rpm ] || packages+=(initscripts)
|
||||
printf 'install %s\n' "${packages[@]}" | sort >"$fixture/expected"
|
||||
sort "$fixture/transactions" >"$fixture/actual"
|
||||
diff -u "$fixture/expected" "$fixture/actual" || {
|
||||
echo "$output" >&2
|
||||
[ ! -f "$fixture/tmp/go-xcat.log" ] || cat "$fixture/tmp/go-xcat.log" >&2
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
@test "RPM uninstall removes all installed OpenEmbedded architectures" { check_uninstall rpm all; }
|
||||
@test "DEB uninstall removes all installed OpenEmbedded architectures" { check_uninstall deb all; }
|
||||
@test "RPM uninstall excludes absent and unrelated packages" { check_uninstall rpm subset; }
|
||||
@test "DEB uninstall excludes absent and unrelated packages" { check_uninstall deb subset; }
|
||||
@test "RPM RISC-V installation selects OpenEmbedded and keeps other packages" { check_install rpm riscv64; }
|
||||
@test "DEB RISC-V installation selects OpenEmbedded and keeps other packages" { check_install deb riscv64; }
|
||||
@test "RPM x86 installation retains its legacy Genesis packages" { check_install rpm x86_64; }
|
||||
@test "DEB x86 installation retains its legacy Genesis packages" { check_install deb x86_64; }
|
||||
@@ -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;
|
||||
@@ -44,6 +44,23 @@ packages, execute target-architecture binaries or prove that the generated image
|
||||
|
||||
## Other native tests
|
||||
|
||||
The pull-request workflow runs these packaging cases explicitly as an ordinary
|
||||
user:
|
||||
|
||||
```
|
||||
prove xCAT-test/native/probe_package_payload.t \
|
||||
xCAT-test/native/release_repository.t \
|
||||
xCAT-test/native/package_relations.t
|
||||
```
|
||||
|
||||
They need RPM build/query tools, cpio, createrepo_c, zstd, rsync, GnuPG, Python 3
|
||||
with RPM bindings, user/mount namespaces, and the Perl modules Capture::Tiny,
|
||||
File::Slurper, Parallel::ForkManager and XML::LibXML. The probe command also
|
||||
needs `which`. The release test uses an ephemeral signing key and removes its
|
||||
agent. These checks inspect real packages and repository output; they do not
|
||||
qualify package installation on every target architecture. On EL8, install both
|
||||
`python36` and `python3-rpm` to provide the interpreter and its RPM bindings.
|
||||
|
||||
Run the package and unprivileged namespace cases as an ordinary user:
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
use File::Temp qw(tempdir);
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
use Test::More;
|
||||
use XCAT::Test::File qw(repo_path);
|
||||
use XCAT::Test::Package qw(run_in);
|
||||
|
||||
plan skip_all => 'requires Linux RPM tooling' unless $^O eq 'linux';
|
||||
local %ENV = (%ENV, HOME => tempdir(CLEANUP => 1));
|
||||
delete @ENV{qw(pcm fsm s390x)};
|
||||
my @platforms = (
|
||||
['EL7', 'rhel 7', 0], ['EL8', 'rhel 8', 1], ['EL9', 'rhel 9', 1],
|
||||
['EL10', 'rhel 10', 1], ['Fedora', 'fedora 44', 1],
|
||||
['SLES12', 'suse_version 1315', 0], ['SLES15', 'suse_version 1500', 1],
|
||||
['openEuler', 'openEuler 2', 0],
|
||||
);
|
||||
my @images = map { "xCAT-genesis-openembedded-$_" } qw(x86_64 ppc64le riscv64 s390x);
|
||||
my %legacy = (x86_64 => 'x86_64', ppc64le => 'ppc64', aarch64 => 'aarch64');
|
||||
for my $platform (@platforms) {
|
||||
my ($name, $macro, $weak) = @$platform;
|
||||
for my $arch (qw(x86_64 ppc64le aarch64 riscv64 s390x)) {
|
||||
for my $pkg (qw(xCAT xCATsn)) {
|
||||
my $requires = query($pkg, $arch, $macro, '--requires');
|
||||
my $recommends = query($pkg, $arch, $macro, '--recommends');
|
||||
unlike($requires, qr/xCAT-genesis-openembedded-/, "$name $arch $pkg never requires optional images");
|
||||
my @actual = sort grep { /^xCAT-genesis-openembedded-/ } split /\n/, $recommends;
|
||||
is_deeply(\@actual, $weak ? [sort @images] : [], "$name $arch $pkg optional image recommendations");
|
||||
my @scripts = grep { /^xCAT-genesis-scripts-/ } split /\n/, $requires;
|
||||
is_deeply(\@scripts, $legacy{$arch}
|
||||
? ["xCAT-genesis-scripts-$legacy{$arch} = 1:9.9.9-1"] : [],
|
||||
"$name $arch $pkg required legacy Genesis scripts");
|
||||
if ($arch eq 'riscv64') {
|
||||
like($requires, $pkg eq 'xCAT' ? qr/^ipmitool-xcat >= 1\.8\.18-4$/m : qr/^ipmitool-xcat >= 1\.8\.17-1$/m,
|
||||
"$name $pkg RISC-V IPMI dependency");
|
||||
unlike($requires, qr/xCAT-genesis-scripts-|xnba-undi|syslinux-xcat|elilo-xcat|%\{/,
|
||||
"$name $pkg RISC-V has no unavailable legacy payload or unresolved macro");
|
||||
}
|
||||
}
|
||||
}
|
||||
for my $s390 (0, 1) {
|
||||
local $ENV{s390x} = $s390;
|
||||
my $requires = query('xCAT-server', 'x86_64', $macro, '--requires');
|
||||
like($requires, qr/^perl\(Digest::SHA\)$/m, "$name server s390x=$s390 requires Digest::SHA");
|
||||
next if $s390;
|
||||
my $recommends = query('xCAT-server', 'x86_64', $macro, '--recommends');
|
||||
is(scalar(grep { $_ eq 'perl-DB_File' } split /\n/, $requires), $name eq 'EL10' ? 0 : 1,
|
||||
"$name server hard DB_File dependency");
|
||||
is(scalar(grep { $_ eq 'perl-DB_File' } split /\n/, $recommends), $name eq 'EL10' ? 1 : 0,
|
||||
"$name server weak DB_File dependency");
|
||||
like($requires, qr/^\Q$_\E$/m, "$name server keeps $_")
|
||||
for qw(perl-Net-Telnet perl-Net-DNS perl-Crypt-CBC perl-Crypt-Rijndael);
|
||||
}
|
||||
}
|
||||
|
||||
for my $platform (@platforms) {
|
||||
my ($name, $macro) = @$platform;
|
||||
my ($rc, $filter, $err) = run_in(repo_path('.'), 'python3', '-c', <<'PY', repo_path('xCAT-server/xCAT-server.spec'), $macro);
|
||||
import rpm, sys
|
||||
for name in ('rhel', 'fedora', 'suse_version', 'openEuler'):
|
||||
rpm.delMacro(name)
|
||||
name, value = sys.argv[2].split()
|
||||
rpm.addMacro(name, value)
|
||||
rpm.addMacro('version', '9.9.9')
|
||||
rpm.addMacro('release', '1')
|
||||
rpm.addMacro('__requires_exclude', '^retained$')
|
||||
rpm.spec(sys.argv[1])
|
||||
print(rpm.expandMacro('%{?__requires_exclude}'))
|
||||
PY
|
||||
is($rc, 0, "$name parses server dependency generator policy") or die($err);
|
||||
chomp $filter;
|
||||
ok('retained' =~ /$filter/, "$name keeps an inherited dependency filter");
|
||||
is('perl(DB_File)' =~ /$filter/ ? 1 : 0, $name eq 'EL10' ? 1 : 0,
|
||||
"$name automatic DB_File dependency exclusion");
|
||||
unlike('perl(Digest::SHA)', qr/$filter/, "$name keeps automatic Digest::SHA dependencies");
|
||||
}
|
||||
|
||||
for my $case (['Linux', 'rhel 8', 'iproute'], ['SUSE', 'suse_version 1500', 'iproute2']) {
|
||||
my ($name, $macro, $provider) = @$case;
|
||||
my $requires = query('xCAT-probe', 'x86_64', $macro, '--requires');
|
||||
my @providers = grep { /^iproute2?$/ } split /\n/, $requires;
|
||||
is_deeply(\@providers, [$provider], "$name probe socket tool provider");
|
||||
}
|
||||
done_testing();
|
||||
|
||||
sub query {
|
||||
my ($package, $arch, $macro, $relation) = @_;
|
||||
my $format = $relation eq '--requires'
|
||||
? '[%{REQUIRENAME} %{REQUIREFLAGS:depflags} %{REQUIREVERSION}\n]'
|
||||
: '[%{RECOMMENDNAME}\n]';
|
||||
my ($rc, $out, $err) = run_in(repo_path('.'), 'rpmspec', '-q', '--target', $arch,
|
||||
(map { ('--undefine', $_) } qw(rhel fedora suse_version openEuler)),
|
||||
'--define', $macro, '--define', 'version 9.9.9', '--define', 'release 1',
|
||||
'--qf', $format, repo_path("$package/$package.spec"));
|
||||
die("$package $arch $macro: $err") if $rc;
|
||||
$out =~ s/[^\S\n]+$//mg;
|
||||
return $out;
|
||||
}
|
||||
@@ -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';
|
||||
die('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);
|
||||
die("@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 die('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 die(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 die("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();
|
||||
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
use File::Copy qw(copy);
|
||||
use File::Path qw(make_path);
|
||||
use File::Slurper qw(read_binary write_text);
|
||||
use File::Temp qw(tempdir);
|
||||
use FindBin;
|
||||
use IO::Uncompress::Gunzip qw(gunzip $GunzipError);
|
||||
use XML::LibXML;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
use Test::More;
|
||||
use XCAT::Test::File qw(repo_path);
|
||||
use XCAT::Test::Package qw(run_in);
|
||||
|
||||
plan skip_all => 'requires Linux package tools' unless $^O eq 'linux';
|
||||
die('run package builds as an unprivileged user') unless $>;
|
||||
my $root = tempdir(CLEANUP => 1);
|
||||
make_path(map { "$root/$_" } qw(home home/keys SOURCES BUILD BUILDROOT RPMS SRPMS SPECS work));
|
||||
chmod 0700, "$root/home/keys" or die $!;
|
||||
local %ENV = (%ENV, HOME => "$root/home", GNUPGHOME => "$root/home/keys", LC_ALL => 'C');
|
||||
delete @ENV{qw(PERL5LIB PERL5OPT PERLLIB)};
|
||||
write_text("$root/home/.rpmmacros", "%__gpg /usr/bin/gpg\n");
|
||||
command($root, 'gpg', '--batch', '--pinentry-mode', 'loopback', '--passphrase', '',
|
||||
'--quick-generate-key', 'Package Test <package@example.test>', 'rsa2048', 'sign', '0');
|
||||
END {
|
||||
local $?;
|
||||
system('gpgconf', '--homedir', "$root/home/keys", '--kill', 'gpg-agent') if defined $root;
|
||||
}
|
||||
command($root, 'tar', '-czf', "$root/SOURCES/xCAT-release-9.9.9.tar.gz",
|
||||
'-C', repo_path('.'), 'xCAT-release');
|
||||
command($root, 'rpmbuild', '-ba', '--define', "_topdir $root",
|
||||
'--define', 'version 9.9.9', '--define', 'release 1', repo_path('xCAT-release/xCAT-release.spec'));
|
||||
my $rpm = 'xCAT-release-9.9.9-1.noarch.rpm';
|
||||
my $srpm = 'xCAT-release-9.9.9-1.src.rpm';
|
||||
ok(-f "$root/RPMS/noarch/$rpm", 'real release RPM was built') or die('missing release RPM');
|
||||
my $requirements = command($root, 'rpm', '-qp', '--requires', "$root/RPMS/noarch/$rpm");
|
||||
like($requirements, qr/^dnf$/m, 'release package requires DNF');
|
||||
my $files = command($root, 'rpm', '-qp', '--qf', '[%{FILENAMES}\t%{FILEFLAGS}\n]', "$root/RPMS/noarch/$rpm");
|
||||
for my $repo (qw(xcat-core xcat-dep xcat-dep-common)) {
|
||||
like($files, qr{^/etc/yum\.repos\.d/\Q$repo\E\.repo\t17$}m, "$repo remains config(noreplace)");
|
||||
}
|
||||
make_path("$root/work/build-utils/lib/XCAT");
|
||||
copy(repo_path('buildrpms.pl'), "$root/work/buildrpms.pl") or die $!;
|
||||
copy(repo_path('build-utils/lib/XCAT/BuildUtils.pm'), "$root/work/build-utils/lib/XCAT/BuildUtils.pm") or die $!;
|
||||
write_text("$root/work/Version", "9.9.9\n");
|
||||
write_text("$root/work/Gitepoch", "1600000000\n");
|
||||
write_text("$root/work/Gitinfo", ('a' x 40) . "\n");
|
||||
make_path("$root/input/SRPMS");
|
||||
copy("$root/RPMS/noarch/$rpm", "$root/input/$rpm") or die $!;
|
||||
copy("$root/SRPMS/$srpm", "$root/input/SRPMS/$srpm") or die $!;
|
||||
copy("$root/RPMS/noarch/$rpm", "$root/input/xCAT-release-latest.noarch.rpm") or die $!;
|
||||
|
||||
for my $signed (0, 1) {
|
||||
for my $attempt (1, 2) {
|
||||
command("$root/work", $^X, 'buildrpms.pl', '--merge-core-repos',
|
||||
'--target', 'alma+epel-10-x86_64', '--release', '1',
|
||||
'--output-dir', "$root/output", '--input-core-repos', "$root/input",
|
||||
$signed ? ('--gpg-sign', '--gpg-key-name', 'package@example.test') : ());
|
||||
check_repository("$root/output", $signed, "merge signed=$signed run=$attempt");
|
||||
}
|
||||
}
|
||||
|
||||
my $target = 'alma+epel-10-x86_64';
|
||||
my $cached = "$root/work/dist/$target/rpms";
|
||||
make_path("$cached/SRPMS", "$root/mock", "$root/locks");
|
||||
copy("$root/RPMS/noarch/$rpm", "$cached/$rpm") or die $!;
|
||||
copy("$root/SRPMS/$srpm", "$cached/SRPMS/$srpm") or die $!;
|
||||
command($root, 'cp', '-a', repo_path('xCAT-release'), "$root/work/xCAT-release");
|
||||
write_text("$root/mock/xCAT-release-$target.cfg", "# cached build\n");
|
||||
write_text("$root/os-release", "ID=almalinux\nVERSION_ID=10\n");
|
||||
local $ENV{BUILD_FIXTURE} = $root;
|
||||
command("$root/work", 'unshare', '--user', '--map-root-user', '--mount',
|
||||
'bash', repo_path('xCAT-test/native/fixtures/buildrpms-namespace.sh'),
|
||||
'sh', '-c', 'trap \'gpgconf --homedir "$GNUPGHOME" --kill gpg-agent\' EXIT; "$@"', 'sign-test',
|
||||
$^X, 'buildrpms.pl', '--package', 'xCAT-release', '--target', $target,
|
||||
'--release', '1', '--nproc', '1', '--gpg-sign', '--gpg-key-name', 'package@example.test');
|
||||
check_repository($cached, 1, 'cached build finalization');
|
||||
|
||||
write_text("$root/work/schedule.pl", <<'PERL');
|
||||
BEGIN {
|
||||
require Parallel::ForkManager;
|
||||
no warnings 'redefine';
|
||||
*Parallel::ForkManager::start = sub {
|
||||
print "scheduled $_[1]\n" if defined $_[1];
|
||||
return 1;
|
||||
};
|
||||
*Parallel::ForkManager::wait_all_children = sub { };
|
||||
}
|
||||
do './buildrpms.pl';
|
||||
die $@ if $@;
|
||||
PERL
|
||||
my $schedule = command("$root/work", 'unshare', '--user', '--map-root-user', '--mount',
|
||||
'bash', repo_path('xCAT-test/native/fixtures/buildrpms-namespace.sh'),
|
||||
$^X, 'schedule.pl', '--target', $target, '--release', '1', '--nproc', '1');
|
||||
is(scalar(grep { $_ eq "scheduled xCAT-release-$target" } split /\n/, $schedule), 1,
|
||||
'default build schedules the release package once');
|
||||
|
||||
unlink "$root/input/$rpm" or die $!;
|
||||
command("$root/work", $^X, 'buildrpms.pl', '--merge-core-repos',
|
||||
'--target', $target, '--release', '1', '--output-dir', "$root/output",
|
||||
'--input-core-repos', "$root/input");
|
||||
ok(!-e "$root/output/xCAT-release-latest.noarch.rpm", 'missing release package leaves no stale alias');
|
||||
is_deeply([primary_packages("$root/output")], [], 'missing release package leaves an empty binary index');
|
||||
done_testing();
|
||||
|
||||
sub command {
|
||||
my ($directory, @args) = @_;
|
||||
my ($rc, $out, $err) = run_in($directory, @args);
|
||||
is($rc, 0, "$args[0] completes") or do { diag($out, $err); die("@args failed"); };
|
||||
return $out;
|
||||
}
|
||||
|
||||
sub primary_packages {
|
||||
my ($directory) = @_;
|
||||
my $repomd = XML::LibXML->load_xml(location => "$directory/repodata/repomd.xml");
|
||||
my ($location) = $repomd->findnodes('//*[local-name()="data"][@type="primary"]/*[local-name()="location"]');
|
||||
die 'missing primary metadata' unless $location;
|
||||
my $path = "$directory/" . $location->getAttribute('href');
|
||||
my $xml;
|
||||
if ($path =~ /\.gz$/) {
|
||||
gunzip $path => \$xml, Transparent => 0 or die $GunzipError;
|
||||
} elsif ($path =~ /\.zst$/) {
|
||||
my ($rc, $out, $err) = run_in($directory, 'zstd', '-dc', $path);
|
||||
die "Cannot decode primary metadata: $err" if $rc;
|
||||
$xml = $out;
|
||||
} else {
|
||||
die "Unsupported primary metadata format: $path";
|
||||
}
|
||||
return XML::LibXML->load_xml(string => $xml)->findnodes('//*[local-name()="package"]');
|
||||
}
|
||||
|
||||
sub check_repository {
|
||||
my ($directory, $signed, $label) = @_;
|
||||
my $alias = "$directory/xCAT-release-latest.noarch.rpm";
|
||||
ok(-f $alias, "$label publishes the alias") or die('missing bootstrap alias');
|
||||
is(read_binary($alias), read_binary("$directory/$rpm"), "$label alias has final RPM bytes");
|
||||
is((stat($alias))[2] & 0777, 0644, "$label alias is readable");
|
||||
my @packages = primary_packages($directory);
|
||||
is(scalar(@packages), 1, "$label indexes the release package once");
|
||||
for my $package (@packages) {
|
||||
my ($location) = $package->findnodes('./*[local-name()="location"]');
|
||||
is($location->getAttribute('href'), $rpm, "$label indexes the versioned filename only");
|
||||
}
|
||||
if ($signed) {
|
||||
for my $repo ($directory, "$directory/SRPMS") {
|
||||
command($root, 'gpg', '--verify', "$repo/repodata/repomd.xml.asc", "$repo/repodata/repomd.xml");
|
||||
}
|
||||
my $signature = command($root, 'rpm', '-qp', '--qf', '%{RSAHEADER:pgpsig}', $alias);
|
||||
like($signature, qr/RSA.*Key ID/i, "$label alias carries the package signature");
|
||||
isnt(read_binary($alias), read_binary("$root/RPMS/noarch/$rpm"), "$label signing changed the unsigned RPM");
|
||||
}
|
||||
}
|
||||
@@ -8,28 +8,6 @@ use Test::More;
|
||||
|
||||
use XCAT::Test::File qw(slurp_repo_file);
|
||||
|
||||
my $rpm_weak_dependencies = join(
|
||||
"\n",
|
||||
'%if 0%{?fedora} || 0%{?rhel} >= 8 || 0%{?suse_version} >= 1500',
|
||||
'Recommends: xCAT-genesis-openembedded-x86_64',
|
||||
'Recommends: xCAT-genesis-openembedded-ppc64le',
|
||||
'Recommends: xCAT-genesis-openembedded-riscv64',
|
||||
'Recommends: xCAT-genesis-openembedded-s390x',
|
||||
'%endif',
|
||||
);
|
||||
|
||||
my $rpm_spec = slurp_repo_file('xCAT/xCAT.spec');
|
||||
like(
|
||||
$rpm_spec,
|
||||
qr/^\Q$rpm_weak_dependencies\E$/m,
|
||||
'RPM weak dependencies stay inside their compatibility guard',
|
||||
);
|
||||
unlike(
|
||||
$rpm_spec,
|
||||
qr/^Requires:\s+xCAT-genesis-openembedded-/m,
|
||||
'missing OpenEmbedded images do not block an RPM upgrade',
|
||||
);
|
||||
|
||||
my $deb_control = slurp_repo_file('xCAT/debian/control');
|
||||
like(
|
||||
$deb_control,
|
||||
@@ -57,13 +35,6 @@ unlike(
|
||||
'missing OpenEmbedded images do not block a DEB upgrade',
|
||||
);
|
||||
|
||||
my $sn_rpm_spec = slurp_repo_file('xCATsn/xCATsn.spec');
|
||||
like(
|
||||
$sn_rpm_spec,
|
||||
qr/^\Q$rpm_weak_dependencies\E$/m,
|
||||
'service-node weak dependencies stay inside their compatibility guard',
|
||||
);
|
||||
|
||||
my $sn_deb_control = slurp_repo_file('xCATsn/debian/control');
|
||||
like(
|
||||
$sn_deb_control,
|
||||
@@ -86,26 +57,6 @@ like(
|
||||
'DEB service nodes recommend the s390x image',
|
||||
);
|
||||
|
||||
my $go_xcat = slurp_repo_file('xCAT-server/share/xcat/tools/go-xcat');
|
||||
unlike(
|
||||
$go_xcat,
|
||||
qr/GO_XCAT_LIBRARY_ONLY/,
|
||||
'go-xcat cannot be disabled by an inherited test environment variable',
|
||||
);
|
||||
for my $architecture (qw(x86 x86_64 ppc64 ppc64le armv7hf aarch64 riscv64 s390x)) {
|
||||
like(
|
||||
$go_xcat,
|
||||
qr/\bxCAT-genesis-openembedded-\Q$architecture\E\b/,
|
||||
"go-xcat removes the $architecture RPM image",
|
||||
);
|
||||
(my $deb_architecture = $architecture) =~ tr/_/-/;
|
||||
like(
|
||||
$go_xcat,
|
||||
qr/\bxcat-genesis-openembedded-\Q$deb_architecture\E\b/,
|
||||
"go-xcat removes the $architecture DEB image",
|
||||
);
|
||||
}
|
||||
|
||||
my $mknb_pod = slurp_repo_file('xCAT-client/pods/man8/mknb.8.pod');
|
||||
like(
|
||||
$mknb_pod,
|
||||
|
||||
@@ -7,66 +7,9 @@ use lib "$FindBin::Bin/../lib";
|
||||
use lib "$FindBin::Bin/../../build-utils/lib";
|
||||
use Test::More;
|
||||
|
||||
use XCAT::Test::File qw(repo_path slurp_repo_file);
|
||||
use XCAT::Test::File qw(repo_path);
|
||||
use XCAT::BuildUtils qw(targetarch_from_target);
|
||||
|
||||
# riscv64 packaging: the arch-named packages (xCAT, xCATsn) must resolve their
|
||||
# architecture token and dependencies for riscv64, and the build scripts must
|
||||
# know the riscv64 package names. The Genesis image comes from the OpenEmbedded
|
||||
# packages, so there is no arch-named Genesis package to resolve here.
|
||||
|
||||
my $xcat = slurp_repo_file('xCAT/xCAT.spec');
|
||||
my ($xcat_rv) = $xcat =~ /^%ifarch riscv64\n((?:#[^\n]*\n|Requires:[^\n]*\n)*)%endif$/m;
|
||||
like( $xcat_rv || '', qr/^Requires: ipmitool-xcat >= 1\.8\.18-4$/m, 'xCAT.spec requires ipmitool-xcat on riscv64' );
|
||||
unlike( $xcat_rv || '', qr/xnba-undi|syslinux-xcat|elilo-xcat/, 'xCAT.spec does not require the x86 PXE loaders on riscv64' );
|
||||
|
||||
# riscv64 has no legacy Genesis package: the requirement must disappear rather than
|
||||
# resolve to an unsatisfiable name, and the OpenEmbedded image is recommended instead.
|
||||
like( $xcat, qr/^%\{\?genesistarch:Requires: xCAT-genesis-scripts-%\{genesistarch\} = 1:%\{version\}-%\{release\}\}$/m, 'xCAT.spec asks for the legacy Genesis package only where the architecture has one' );
|
||||
like( $xcat, qr/^Recommends: xCAT-genesis-openembedded-riscv64$/m, 'xCAT.spec recommends the RISC-V OpenEmbedded Genesis image' );
|
||||
|
||||
SKIP: {
|
||||
my $rpmspec = qx(command -v rpmspec 2>/dev/null);
|
||||
chomp($rpmspec);
|
||||
skip 'rpmspec is not installed', 2 unless $rpmspec && -x $rpmspec;
|
||||
|
||||
my $spec = repo_path('xCAT/xCAT.spec');
|
||||
open( my $requires_fh, '-|',
|
||||
$rpmspec, '-q', '--target', 'riscv64', '--requires', $spec )
|
||||
or BAIL_OUT("unable to run $rpmspec: $!");
|
||||
my $requires = do { local $/; <$requires_fh> };
|
||||
close($requires_fh)
|
||||
or BAIL_OUT("rpmspec failed for $spec with status " . ($? >> 8));
|
||||
|
||||
unlike( $requires, qr/genesis-scripts/, 'a riscv64 build requires no legacy Genesis package' );
|
||||
unlike( $requires, qr/\Q%{genesistarch}\E/, 'a riscv64 build leaves no unexpanded architecture macro' );
|
||||
}
|
||||
|
||||
my $xcatsn = slurp_repo_file('xCATsn/xCATsn.spec');
|
||||
my ($xcatsn_rv) = $xcatsn =~ /^%ifarch [^\n]*\briscv64\b[^\n]*\n((?:#[^\n]*\n|Requires:[^\n]*\n)*)%endif$/m;
|
||||
like( $xcatsn_rv || '', qr/^Requires: ipmitool-xcat >= 1\.8\.17-1$/m, 'xCATsn.spec requires ipmitool-xcat on riscv64' );
|
||||
like( $xcatsn, qr/^Recommends: xCAT-genesis-openembedded-riscv64$/m, 'xCATsn.spec recommends the RISC-V OpenEmbedded Genesis image' );
|
||||
|
||||
my $server = slurp_repo_file('xCAT-server/xCAT-server.spec');
|
||||
like( $server, qr/^Recommends: perl-DB_File$/m, 'xCAT-server.spec recommends perl-DB_File on EL10 (riscv64 has no EPEL to provide it)' );
|
||||
like(
|
||||
$server,
|
||||
qr/^%if 0%\{\?rhel\} >= 10\nRecommends: perl-DB_File\n/m,
|
||||
'the weak perl-DB_File dependency is limited to EL10, where riscv64 has no EPEL',
|
||||
);
|
||||
like(
|
||||
$server,
|
||||
qr/^%else\nRequires: perl-DB_File\n%endif$/m,
|
||||
'build hosts without weak dependencies keep the hard perl-DB_File requirement',
|
||||
);
|
||||
like(
|
||||
$server,
|
||||
qr/^%global __requires_exclude %\{\?__requires_exclude:%\{__requires_exclude\}\|\}\^perl\\\\\(DB_File\\\\\)\$$/m,
|
||||
'xCAT-server.spec appends the generated perl(DB_File) requirement to the build root filter',
|
||||
);
|
||||
like( $server, qr/^Requires: perl-Net-Telnet perl-Net-DNS perl-Crypt-CBC perl-Crypt-Rijndael$/m, 'xCAT-server.spec keeps the other EL perl requires' );
|
||||
|
||||
|
||||
my $architectures = repo_path('build-utils/rpm-architectures.sh');
|
||||
is(system('sh', '-n', $architectures), 0, 'the shared build architecture data parses as POSIX shell');
|
||||
open(
|
||||
@@ -75,9 +18,9 @@ open(
|
||||
'sh', '-c',
|
||||
'. "$1"; printf "%s\n%s\n%s\n" "$XCAT_CORE_RPM_ARCHES" "$XCAT_LOCAL_RPM_ARCHES" "$XCAT_LOCAL_COLLECT_ARCHES"',
|
||||
'sh', $architectures,
|
||||
) or BAIL_OUT("unable to load $architectures: $!");
|
||||
) or die("unable to load $architectures: $!");
|
||||
my @architecture_sets = <$arch_fh>;
|
||||
close($arch_fh) or BAIL_OUT("unable to read architecture data from $architectures");
|
||||
close($arch_fh) or die("unable to read architecture data from $architectures");
|
||||
chomp @architecture_sets;
|
||||
|
||||
is(
|
||||
|
||||
@@ -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 // '');
|
||||
}
|
||||
|
||||
@@ -3,13 +3,12 @@ use strict;
|
||||
use warnings;
|
||||
|
||||
use Digest::SHA qw(sha256_hex);
|
||||
use File::Spec;
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
use Test::More;
|
||||
use XCAT::Test::File qw(slurp_repo_file);
|
||||
|
||||
my $repo_root = File::Spec->rel2abs(File::Spec->catdir($FindBin::Bin, '..', '..'));
|
||||
|
||||
my $spec = read_file('xCAT-release/xCAT-release.spec');
|
||||
my $spec = slurp_repo_file('xCAT-release/xCAT-release.spec');
|
||||
like($spec, qr/^Name:\s+xCAT-release$/m, 'package has the expected name');
|
||||
like($spec, qr/^Source0:\s+xCAT-release-%\{version\}\.tar\.gz$/m, 'source archive follows the package name');
|
||||
like($spec, qr/^BuildArch:\s+noarch$/m, 'package is architecture independent');
|
||||
@@ -19,7 +18,7 @@ like($spec, qr/^%config\(noreplace\) .*xcat-dep\.repo$/m, 'dependency repo prese
|
||||
like($spec, qr/^%config\(noreplace\) .*xcat-dep-common\.repo$/m, 'common dependency repo preserves local changes');
|
||||
like($spec, qr{RPM-GPG-KEY-xCAT}, 'package installs the signing key');
|
||||
|
||||
my $core = read_file('xCAT-release/xcat-core.repo');
|
||||
my $core = slurp_repo_file('xCAT-release/xcat-core.repo');
|
||||
assert_repo_security($core, 'core');
|
||||
like(
|
||||
$core,
|
||||
@@ -27,7 +26,7 @@ like(
|
||||
'core repo uses the stable HTTPS endpoint'
|
||||
);
|
||||
|
||||
my $dep = read_file('xCAT-release/xcat-dep.repo');
|
||||
my $dep = slurp_repo_file('xCAT-release/xcat-dep.repo');
|
||||
assert_repo_security($dep, 'dependency');
|
||||
like(
|
||||
$dep,
|
||||
@@ -35,7 +34,7 @@ like(
|
||||
'dependency repo follows the DNF release and architecture variables'
|
||||
);
|
||||
|
||||
my $common_dep = read_file('xCAT-release/xcat-dep-common.repo');
|
||||
my $common_dep = slurp_repo_file('xCAT-release/xcat-dep-common.repo');
|
||||
assert_repo_security($common_dep, 'common dependency');
|
||||
like(
|
||||
$common_dep,
|
||||
@@ -48,7 +47,7 @@ like(
|
||||
'common dependency repo is independent of the management-node distribution'
|
||||
);
|
||||
|
||||
my $key = read_file('xCAT-release/RPM-GPG-KEY-xCAT');
|
||||
my $key = slurp_repo_file('xCAT-release/RPM-GPG-KEY-xCAT');
|
||||
like($key, qr/^-----BEGIN PGP PUBLIC KEY BLOCK-----$/m, 'signing key is ASCII armored');
|
||||
is(
|
||||
sha256_hex($key),
|
||||
@@ -56,40 +55,6 @@ is(
|
||||
'packaged key matches the published xCAT signing key'
|
||||
);
|
||||
|
||||
my $builder = read_file('buildrpms.pl');
|
||||
like($builder, qr/^\s+xCAT-release\s*$/m, 'default RPM build includes xCAT-release');
|
||||
like(
|
||||
$builder,
|
||||
qr{\$repodir/xCAT-release-latest\.noarch\.rpm},
|
||||
'stable bootstrap alias follows the package name'
|
||||
);
|
||||
like(
|
||||
$builder,
|
||||
qr{\$repodir/xCAT-release-\$VERSION-\$RELEASE\.noarch\.rpm},
|
||||
'stable bootstrap alias selects the xCAT-release RPM'
|
||||
);
|
||||
like(
|
||||
$builder,
|
||||
qr/unlink \$alias.*?createrepo_dir\(\$repodir/s,
|
||||
'stable bootstrap alias is excluded from repository metadata'
|
||||
);
|
||||
like(
|
||||
$builder,
|
||||
qr/cp \$release_rpms\[0\], \$alias/,
|
||||
'repository export creates the stable bootstrap filename'
|
||||
);
|
||||
my $sign_call = rindex($builder, 'sign_rpms($target)');
|
||||
my $alias_call = rindex($builder, 'write_release_alias("dist/$target/rpms")');
|
||||
ok(
|
||||
$sign_call >= 0 && $alias_call > $sign_call,
|
||||
'stable bootstrap alias is created after signed metadata is finalized'
|
||||
);
|
||||
like(
|
||||
$builder,
|
||||
qr/sub merge_core_repos \{.*?write_repo_metadata_dir\(\$out\);.*?write_release_alias\(\$out\);/s,
|
||||
'assembled core repository creates the stable alias after final metadata'
|
||||
);
|
||||
|
||||
done_testing();
|
||||
|
||||
sub assert_repo_security {
|
||||
@@ -103,12 +68,3 @@ sub assert_repo_security {
|
||||
"$label repo uses the packaged signing key"
|
||||
);
|
||||
}
|
||||
|
||||
sub read_file {
|
||||
my ($file) = @_;
|
||||
my $path = File::Spec->catfile($repo_root, split m{/}, $file);
|
||||
open(my $fh, '<', $path) or die "open $path: $!";
|
||||
my $contents = do { local $/; <$fh> };
|
||||
close($fh) or die "close $path: $!";
|
||||
return $contents;
|
||||
}
|
||||
|
||||
@@ -1,42 +1,14 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::Spec;
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
use Test::More;
|
||||
use XCAT::Test::File qw(slurp_repo_file);
|
||||
|
||||
my $repo_root = File::Spec->rel2abs(
|
||||
File::Spec->catdir( $FindBin::Bin, '..', '..' )
|
||||
);
|
||||
|
||||
sub read_file {
|
||||
my ($filename) = @_;
|
||||
open( my $fh, '<', $filename )
|
||||
or die "Unable to read $filename: $!";
|
||||
my $content = do { local $/; <$fh> };
|
||||
close($fh);
|
||||
return $content;
|
||||
}
|
||||
|
||||
my $rpm_spec = read_file(
|
||||
File::Spec->catfile( $repo_root, 'xCAT-server', 'xCAT-server.spec' )
|
||||
);
|
||||
my @rpm_sha_requirements =
|
||||
$rpm_spec =~ /^Requires:.*\bperl\(Digest::SHA\)(?:\s|$)/mg;
|
||||
is(
|
||||
scalar(@rpm_sha_requirements),
|
||||
2,
|
||||
'both RPM architecture branches require Digest::SHA',
|
||||
);
|
||||
|
||||
my $debian_control = read_file(
|
||||
File::Spec->catfile( $repo_root, 'xCAT-server', 'debian', 'control' )
|
||||
);
|
||||
like(
|
||||
$debian_control,
|
||||
qr/^Depends:.*\blibdigest-sha-perl\b/m,
|
||||
'the Debian package requires Digest::SHA',
|
||||
);
|
||||
my $control = slurp_repo_file('xCAT-server/debian/control');
|
||||
my ($server) = $control =~ /^Package: xcat-server\n(.*?)(?:\n\n|\z)/ms;
|
||||
like($server // '', qr/^Depends:.*\blibdigest-sha-perl\b/m,
|
||||
'the Debian server package requires Digest::SHA');
|
||||
|
||||
done_testing();
|
||||
|
||||
Reference in New Issue
Block a user