From b0bf36d27a5229ed7777207dde7e72f58c2b8a0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Sat, 5 Sep 2026 01:49:10 -0300 Subject: [PATCH] test(xCAT-test): cover the riscv64 Ubuntu management node packaging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends the builder tests with the per-package architecture lists and the architectures a release declares, and adds the generated mklocalrepo.sh mapping a riscv64 host to its own repository. Also checks that xcat and xcatsn declare riscv64 without losing amd64 or ppc64el. Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com> --- xCAT-test/unit/build_utils.t | 18 +++--- xCAT-test/unit/builddebs_riscv64.t | 88 ++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 xCAT-test/unit/builddebs_riscv64.t diff --git a/xCAT-test/unit/build_utils.t b/xCAT-test/unit/build_utils.t index 8a44fbe39..eaa3a43ff 100644 --- a/xCAT-test/unit/build_utils.t +++ b/xCAT-test/unit/build_utils.t @@ -60,15 +60,19 @@ is_deeply( [deb_package_arches('perl-xCAT')], ['all'], 'a Perl package is built once, arch-independent' ); is_deeply( [deb_package_arches('xCAT-probe')], ['all'], 'xCAT-probe is arch-independent too' ); -for my $pkg (qw(xCAT xCATsn xCAT-genesis-scripts)) { - is_deeply( [deb_package_arches($pkg)], ['amd64', 'ppc64el'], - "$pkg is built per architecture" ); +for my $pkg (qw(xCAT xCATsn)) { + is_deeply( [deb_package_arches($pkg)], ['amd64', 'ppc64el', 'riscv64'], + "$pkg is built for every architecture a management node runs on" ); } +# xCAT-genesis-scripts has one control file per architecture and there is no riscv64 one, +# so asking for that build would stop the whole run. +is_deeply( [deb_package_arches('xCAT-genesis-scripts')], ['amd64', 'ppc64el'], + 'xCAT-genesis-scripts is built only for the architectures it has a control file for' ); is_deeply( [deb_package_arches(undef)], ['all'], 'an undefined package name does not blow up the arch lookup' ); -is_deeply( [dist_arches('noble')], ['amd64', 'ppc64el'], - 'a current release serves both architectures' ); +is_deeply( [dist_arches('noble')], ['amd64', 'ppc64el', 'riscv64'], + 'a current release serves every architecture' ); is_deeply( [dist_arches('saucy')], ['amd64'], 'saucy predates ppc64el and serves only amd64' ); @@ -151,8 +155,8 @@ is( scalar( () = $rewritten =~ /^ -- xCAT Build /mg ), 1, my $dists = reprepro_distributions([qw(focal noble)], 'DEADBEEF'); is( scalar(() = $dists =~ /^Codename:/mg), 2, 'one stanza per release' ); -like( $dists, qr/^Codename: focal\nArchitectures: amd64 ppc64el$/m, - 'a release declares both architectures, on the line after its codename' ); +like( $dists, qr/^Codename: focal\nArchitectures: amd64 ppc64el riscv64$/m, + 'a release declares every architecture, on the line after its codename' ); is( scalar(() = $dists =~ /^SignWith: DEADBEEF$/mg), 2, 'every stanza is signed when a key is given' ); diff --git a/xCAT-test/unit/builddebs_riscv64.t b/xCAT-test/unit/builddebs_riscv64.t new file mode 100644 index 000000000..5dc2fc813 --- /dev/null +++ b/xCAT-test/unit/builddebs_riscv64.t @@ -0,0 +1,88 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use File::Spec; +use File::Temp qw(tempdir); +use FindBin; +use Test::More; + +# A riscv64 management node needs an xcat and xcatsn deb built for the architecture and a +# mklocalrepo.sh that points the host at the matching repository instead of amd64. +# +# The generated script is extracted from builddebs.pl and run with a stub uname ahead of +# $PATH, so the mapping under test is the shipped code. Only the path it writes is +# redirected into the sandbox, because it writes an apt source list. + +my $repo_root = File::Spec->rel2abs( File::Spec->catdir( $FindBin::Bin, '..', '..' ) ); +my $builder = File::Spec->catfile( $repo_root, 'builddebs.pl' ); +plan skip_all => "builddebs.pl not found" unless -f $builder; + +my $src = do { local $/; open my $fh, '<', $builder or die $!; <$fh> }; + +# BAIL_OUT rather than skip: a rename that stops this matching must fail loudly instead of +# silently covering nothing. +my ($script) = $src =~ /write_script\("\$repodir\/mklocalrepo\.sh", <<'SCRIPT'\);\n(.*?)\nSCRIPT\n/ms; +BAIL_OUT('could not extract mklocalrepo.sh from builddebs.pl') unless defined $script; + +my $dir = tempdir( CLEANUP => 1 ); +my $run = 0; + +# Run the generated script for one host architecture and return the apt source line it wrote. +sub sources_line_for { + my ($uname) = @_; + $run++; + my $root = File::Spec->catdir( $dir, "run$run" ); + mkdir $root; + mkdir "$root/bin"; + + open( my $stub, '>', "$root/bin/uname" ) or die $!; + print {$stub} "#!/bin/bash\necho $uname\n"; + close($stub); + chmod 0755, "$root/bin/uname"; + + my $release = File::Spec->catfile( $root, 'lsb-release' ); + open( my $rel, '>', $release ) or die $!; + print {$rel} "DISTRIB_CODENAME=noble\n"; + close($rel); + + my $listed = File::Spec->catfile( $root, 'sources.list' ); + ( my $sandboxed = $script ) =~ s{/etc/lsb-release}{$release}; + $sandboxed =~ s{/etc/apt/sources\.list\.d/\S+}{$listed}; + + my $harness = File::Spec->catfile( $root, 'harness.sh' ); + open( my $fh, '>', $harness ) or die $!; + print {$fh} "#!/bin/bash\n$sandboxed\n"; + close($fh); + + local $ENV{PATH} = "$root/bin:$ENV{PATH}"; + system( '/bin/bash', $harness ); + open( my $out, '<', $listed ) or die $!; + my $line = do { local $/; <$out> }; + close($out); + return $line; +} + +for my $case ( + [ 'riscv64', 'riscv64' ], + [ 'ppc64le', 'ppc64el' ], + [ 'x86_64', 'amd64' ], + ) +{ + my ( $uname, $want ) = @$case; + like( sources_line_for($uname), qr/^deb \[arch=\Q$want\E\] /, + "mklocalrepo.sh gives a $uname host the $want repository" ); +} + +# The debs themselves must exist for the architecture. +for my $case ( [ 'xCAT', 'xcat' ], [ 'xCATsn', 'xcatsn' ] ) { + my ( $component, $package ) = @$case; + my $control = File::Spec->catfile( $repo_root, $component, 'debian', 'control' ); + my $text = do { local $/; open my $fh, '<', $control or die $!; <$fh> }; + my ($arches) = $text =~ /^Package: \Q$package\E\nArchitecture: (.*)$/m; + ok( defined $arches, "$package declares an architecture" ); + like( $arches || '', qr/\briscv64\b/, "$package is built for riscv64" ); + like( $arches || '', qr/\bamd64\b.*\bppc64el\b/, "$package keeps amd64 and ppc64el" ); +} + +done_testing();