2
0
mirror of https://github.com/xcat2/xcat-dep.git synced 2026-10-17 17:20:31 +00:00

Merge master into fix/openeuler-ppc64le-net-dns

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
This commit is contained in:
Daniel Hilst
2026-10-14 11:08:27 -03:00
8 changed files with 463 additions and 19 deletions
+11 -1
View File
@@ -23,7 +23,14 @@ jobs:
sudo apt-get install -y --no-install-recommends \
apt-utils bats createrepo-c dpkg-dev gnupg \
libfile-slurper-perl \
libparallel-forkmanager-perl libperl-critic-perl rpm rpm2cpio cpio
libparallel-forkmanager-perl libperl-critic-perl rpm rpm2cpio cpio \
grub-common ca-certificates
- name: Install the arm64-efi grub modules
# t/aarch64_target.t runs the spec's own grub2-mkimage command, and it skips without
# the arm64-efi modules -- a skip exactly where the suite runs. The script reads them
# from the runner's own suite through apt's signed metadata.
run: sudo ./install-grub-arm64-modules.sh
- name: Run static checks
run: |
@@ -75,6 +82,8 @@ jobs:
prove -v -It/lib t/genesis_openembedded_release.t
sudo -E prove -v -It/lib t/genesis_openembedded_consumer.t
prove -v t/riscv64_perl_cell.t
prove -v t/aarch64_target.t
prove -v t/aarch64_cross_build.t
sudo -E prove -v -It/lib t/common-repo-gate.t
prove -v t/openeuler.t
prove -v t/openeuler_mock_template_include.t
@@ -85,6 +94,7 @@ jobs:
prove -v -Ilib t/openeuler_native_trust_dbpath.t
prove -v -Ilib t/openeuler_native_cpio_scan.t
bats t/verify-xcatsn-install.bats
bats t/install-grub-arm64-modules.bats
# Ubuntu's AppArmor policy blocks these unprivileged test namespaces.
- name: Run native packaging tests
+11
View File
@@ -395,6 +395,17 @@ tracked prebuilt EFI payload and `syslinux-xcat` installs the prebuilt bootloade
release tarball, so the noarch rpms carry the same payload as the ppc64le build. aarch64 is not
part of the `--finalize-xcat-dep` cross-arch genesis copy.
`aarch64` also builds on an x86_64 host. mock applies `--forcearch=aarch64` to the
`alma+epel-10-aarch64` config when the host is not aarch64, so the chroot runs aarch64 binaries
through `qemu-aarch64-static` and produces aarch64 rpms. The host needs that emulator and its
`binfmt_misc` handler; without them mock warns at the start of the build and the chroot cannot run
its own rpm scriptlets. EL packages no `qemu-user-static`, so take the static binary from a Fedora
container, as the riscv64 host prerequisites do.
A cross-build is slower than a native one and is otherwise the same build: the rpms and the
repository cell carry the target architecture, not the host one, and the step timeout is the
emulated bound.
# riscv64 (EL10): cross-building on an x86_64 host
There is no riscv64 build host in the xCAT build farm and no EPEL for riscv64, so the
+34 -1
View File
@@ -25,7 +25,7 @@ our @EXPORT_OK = qw(
cross_copy_genesis finalize_xcat_dep bump_dep_release_suffix
createrepo_c_cmd sign_and_index_repo
build_mock_uniqueext rpm_in_cell resolve_mock_cfg mock_chroot_uid mock_result_dirs
make_traversable_path
make_traversable_path epel_target_profile epel_cell_path cell_lock_path
native_owner_command NATIVE_BUILD_GID
openeuler_build_target openeuler_repo_subdir
recover_common_repository
@@ -896,6 +896,39 @@ sub recover_common_repository {
return 1;
}
# epel_target_profile($target, $host_arch): the EL release, the rpm architecture, and whether
# mock cross-builds, for one EPEL target name on one build host. Returns undef for a name that is
# not an EPEL target, so the caller keeps its own error.
#
# The target name carries the architecture of the rpms it produces, and that architecture decides
# the repository cell the build deploys to. A host of another architecture cross-builds the target
# through mock's own --forcearch and qemu-user; the rpms are still the target's architecture.
sub epel_target_profile {
my ($target, $host_arch) = @_;
return undef unless defined $target && defined $host_arch;
my ($rel, $arch) = $target =~ /epel-(\d+)-(.+)\z/;
return undef unless defined $rel && defined $arch;
return { rel => $rel, arch => $arch, forcearch => ($arch eq $host_arch ? 0 : 1) };
}
# epel_cell_path($repo_dep, $profile): the repository cell an EPEL target deploys,
# <repo-dep>/rh<rel>/<arch>, from the profile epel_target_profile returns.
#
# The deploy, the carry-over and the cell lock all take the path from here, so the lock covers the
# directory the deploy writes. Two targets share a lock exactly when they share a cell.
sub epel_cell_path {
my ($repo_dep, $profile) = @_;
return undef unless defined $repo_dep && $profile;
return "$repo_dep/rh$profile->{rel}/$profile->{arch}";
}
# cell_lock_path($cell): the lock of a repository cell <dir>/<arch> sits beside it, as
# <dir>/.<arch>.lock, because the deploy replaces the cell directory itself.
sub cell_lock_path {
my ($cell) = @_;
return dirname($cell) . '/.' . basename($cell) . '.lock';
}
# resolve_mock_cfg($os_id, $rel, $arch[, $cfg_dir]): the mock config for EL release $rel on this
# host, <id>+epel-<rel>-<arch>. /etc/os-release says 'almalinux' where mock-core-configs names the
# file 'alma', so the short form is tried too. $cfg_dir defaults to /etc/mock.
+154
View File
@@ -0,0 +1,154 @@
#!/bin/bash
# Install the arm64-efi GRUB modules, so a host grub-mkimage can build the AArch64
# network loader of grub2-xcat.spec. Ubuntu ships them only in grub-efi-arm64-bin,
# which is Architecture: arm64 and does not install on an amd64 host. The deb is read
# through apt's signed metadata, unpacked in a temporary directory, and only the
# module files are copied out.
#
# grub-mkimage embeds kernel.img and resolves moddep.lst from the module directory,
# so the modules must come from the GRUB version of the host tool.
usage() {
cat <<'EOF'
Usage: install-grub-arm64-modules.sh [-d DESTDIR] [-s SUITE] [-m MIRROR]
-d DESTDIR where the modules go (default /usr/lib/grub/arm64-efi)
-s SUITE suite to read (default: VERSION_CODENAME of /etc/os-release)
-m MIRROR apt mirror (default https://ports.ubuntu.com/ubuntu-ports)
apt verifies the suite InRelease signature with the host keyring, and the deb hash
against that signed index. The deb is unpacked under ${TMPDIR:-/tmp} and removed on
exit. Nothing else from it is installed.
EOF
}
PACKAGE=grub-efi-arm64-bin
MODULE_PATH=usr/lib/grub/arm64-efi
MIRROR_DEFAULT=https://ports.ubuntu.com/ubuntu-ports
# Prints the GRUB upstream version of the host image builder, e.g. 2.12.
# EL names the tool grub2-mkimage and Debian names it grub-mkimage.
host_grub_version() {
local tool out
for tool in grub2-mkimage grub-mkimage; do
command -v "$tool" >/dev/null 2>&1 || continue
out=$("$tool" --version 2>/dev/null) || continue
# "grub-mkimage (GRUB) 2.12-1ubuntu7.3"
out=${out##* }
echo "${out%%-*}"
return 0
done
echo "no grub2-mkimage and no grub-mkimage on PATH" >&2
return 1
}
# The upstream version of a deb version: no epoch, no distribution revision.
upstream_version() {
local v=${1#*:}
echo "${v%%-*}"
}
# apt-get against a private state tree, so the host dpkg architecture and the host
# sources stay as they are. An unsigned or stale index fails here.
apt_get() {
local root=$1
shift
apt-get \
-o Dir::State="$root/state" \
-o Dir::State::status="$root/status" \
-o Dir::Cache="$root/cache" \
-o Dir::Etc::SourceList="$root/sources.list" \
-o Dir::Etc::SourceParts="$root/none" \
-o Dir::Etc::Preferences="$root/none/preferences" \
-o Dir::Etc::PreferencesParts="$root/none" \
-o APT::Architecture=arm64 \
-o APT::Architectures=arm64 \
-o APT::Sandbox::User=root \
-o Acquire::AllowInsecureRepositories=false \
-o APT::Get::AllowUnauthenticated=false \
"$@"
}
main() {
local dest=/usr/lib/grub/arm64-efi suite='' mirror=$MIRROR_DEFAULT opt
OPTIND=1
while getopts 'd:s:m:h' opt; do
case $opt in
d) dest=$OPTARG ;;
s) suite=$OPTARG ;;
m) mirror=$OPTARG ;;
h) usage; return 0 ;;
*) usage >&2; return 2 ;;
esac
done
shift $((OPTIND - 1))
if (( $# != 0 )); then
usage >&2
return 2
fi
if [[ -z $suite ]]; then
suite=$(. /etc/os-release 2>/dev/null && echo "$VERSION_CODENAME")
fi
if [[ -z $suite ]]; then
echo "no suite: /etc/os-release names no VERSION_CODENAME, give -s" >&2
return 2
fi
local want
want=$(host_grub_version) || return 1
local root
root=$(mktemp -d "${TMPDIR:-/tmp}/grub-arm64.XXXXXX") || return 1
# shellcheck disable=SC2064
trap "rm -rf '$root'" EXIT
mkdir -p "$root/state/lists/partial" "$root/cache/archives/partial" "$root/none" "$root/deb" || return 1
: > "$root/status"
printf 'deb [arch=arm64] %s %s main\n' "$mirror" "$suite" > "$root/sources.list" || return 1
if ! apt_get "$root" update; then
echo "FAIL: apt-get update of $mirror $suite failed" >&2
return 1
fi
if ! (cd "$root/deb" && apt_get "$root" download "$PACKAGE"); then
echo "FAIL: apt-get download $PACKAGE from $suite failed" >&2
return 1
fi
local deb
deb=$(find "$root/deb" -maxdepth 1 -name "${PACKAGE}_*_arm64.deb" | sort | head -1)
if [[ -z $deb ]]; then
echo "FAIL: apt downloaded no $PACKAGE deb" >&2
return 1
fi
local got
got=$(dpkg-deb -f "$deb" Version) || return 1
got=$(upstream_version "$got")
if [[ $got != "$want" ]]; then
echo "FAIL: $PACKAGE is GRUB $got and the host image builder is GRUB $want" >&2
return 1
fi
dpkg-deb -x "$deb" "$root/x" || return 1
if [[ ! -d $root/x/$MODULE_PATH ]]; then
echo "FAIL: $PACKAGE carries no $MODULE_PATH" >&2
return 1
fi
# The modules, moddep.lst and kernel.img, and none of the documentation or the
# prebuilt images under monolithic/ that the deb also carries.
install -d "$dest" || return 1
find "$root/x/$MODULE_PATH" -maxdepth 1 -type f -exec install -m 0644 -t "$dest" {} + || return 1
local count
count=$(find "$dest" -maxdepth 1 -name '*.mod' | wc -l)
if (( count == 0 )) || [[ ! -f $dest/kernel.img || ! -f $dest/moddep.lst ]]; then
echo "FAIL: $dest has no modules, no kernel.img or no moddep.lst" >&2
return 1
fi
echo "PASS: $count arm64-efi modules of GRUB $got in $dest, from ${deb##*/}"
}
if [[ ${BASH_SOURCE[0]} == "$0" ]]; then
main "$@"
fi
+10 -15
View File
@@ -19,7 +19,7 @@ use FindBin qw($RealBin);
use lib $RealBin, "$RealBin/lib";
use XCAT::NFSLock ();
use MockBuildUtils qw(sh_quote print_step version_matches required_pkgs rpm_in_cell resolve_mock_cfg
NATIVE_BUILD_GID
NATIVE_BUILD_GID epel_target_profile epel_cell_path cell_lock_path
carry_over_rpms rpm_name rpm_arch rpm_source_rpm rpm_digests_ok
install_deps_packages install_deps_command missing_perl_modules
read_manifest derive_target_from_repo_path
@@ -1179,13 +1179,16 @@ sub target_profile {
epel => 0,
};
}
my ($rel) = $target =~ /epel-(\d+)-/;
die "Could not parse EL release from target '$target'\n" unless defined $rel;
# The target name, not the host, decides the architecture of the rpms and so the repository
# cell they deploy to. A host of another architecture cross-builds the target through mock's
# own --forcearch, which is what gives the emulated build its own step timeout below.
my $epel = epel_target_profile($target, $host_arch);
die "Could not parse EL release from target '$target'\n" unless $epel;
return {
rel => $rel,
arch => $host_arch,
rel => $epel->{rel},
arch => $epel->{arch},
noarch_cfg => $target,
forcearch => 0,
forcearch => $epel->{forcearch},
epel => 1,
dep_builders => [qw(elilo-xcat grub2-xcat ipmitool-xcat syslinux-xcat goconserver conserver-xcat xnba-undi ipxe-xcat)],
# xCAT Requires all of these on every arch, and every one of them builds natively on
@@ -2490,15 +2493,7 @@ sub target_cell {
my ($target) = @_;
my $native = openeuler_repo_subdir($target);
return "$repo_dep/$native" if defined $native;
my $profile = target_profile($target);
return "$repo_dep/rh$profile->{rel}/$profile->{arch}";
}
# The lock of a repository cell <dir>/<arch> sits beside it, as <dir>/.<arch>.lock: the deploy
# replaces the cell directory itself.
sub cell_lock_path {
my ($cell) = @_;
return dirname($cell) . '/.' . basename($cell) . '.lock';
return epel_cell_path($repo_dep, target_profile($target));
}
# Release locks on every exit path, but only from the process that acquired them.
+73
View File
@@ -0,0 +1,73 @@
#!/usr/bin/env perl
# An EPEL target names the architecture of the rpms it produces, and that architecture decides
# the repository cell the build deploys to. A build host whose own architecture differs
# cross-builds the target through mock's --forcearch and qemu-user; the rpms are still the
# target's architecture.
#
# alma+epel-10-aarch64 built on an x86_64 host reported arch=x86_64, so target_cell resolved to
# rh10/x86_64 and the aarch64 build would have replaced the x86_64 cell of the published
# repository with aarch64 rpms. It also reported forcearch=0, which left the emulated build with
# the native step timeout.
use strict;
use warnings;
use FindBin qw($RealBin);
use Test::More;
use lib $RealBin, "$RealBin/..";
use MockBuildUtils qw(epel_target_profile epel_cell_path cell_lock_path);
# A cross-built target: the rpms and the cell are the target's architecture, not the host's.
{
my $p = epel_target_profile('alma+epel-10-aarch64', 'x86_64');
ok($p, 'alma+epel-10-aarch64 is an EPEL target') or done_testing, exit;
is($p->{rel}, '10', 'EL release 10');
is($p->{arch}, 'aarch64', 'the rpm architecture is the target architecture, not the host one');
is($p->{forcearch}, 1, 'an x86_64 host cross-builds it');
}
# The same target on its own architecture is a native build.
{
my $p = epel_target_profile('alma+epel-10-aarch64', 'aarch64');
is($p->{arch}, 'aarch64', 'a native aarch64 build still produces aarch64 rpms');
is($p->{forcearch}, 0, 'and does not cross-build');
}
# Every target that builds today keeps the answer it has today: same arch, no cross-build.
for my $case (['alma+epel-10-x86_64', 'x86_64', '10'],
['alma+epel-9-x86_64', 'x86_64', '9'],
['alma+epel-8-x86_64', 'x86_64', '8'],
['alma+epel-10-ppc64le', 'ppc64le', '10'],
['alma+epel-9-ppc64le', 'ppc64le', '9'],
['alma+epel-8-ppc64le', 'ppc64le', '8'])
{
my ($target, $host, $rel) = @$case;
my $p = epel_target_profile($target, $host);
is($p->{rel}, $rel, "$target on $host: EL release $rel");
is($p->{arch}, $host, "$target on $host: builds natively for $host");
is($p->{forcearch}, 0, "$target on $host: no cross-build");
}
# The two EL10 targets deploy to different cells, so they take different cell locks. With the
# architecture taken from the host, both resolved to rh10/x86_64 and to one lock: the aarch64 build
# on xcat-master held .x86_64.lock, and the x86_64 build of the same run waited out its 100 retries
# and exited before it built anything (xcat-dep-build-el10-x86_64 builds 92 and 93).
{
my $repo = '/repo/yum/xcat-dep';
my %cell = map { $_ => epel_cell_path($repo, epel_target_profile("alma+epel-10-$_", 'x86_64')) }
qw(x86_64 aarch64);
is($cell{aarch64}, "$repo/rh10/aarch64", 'the aarch64 target deploys to the aarch64 cell');
is($cell{x86_64}, "$repo/rh10/x86_64", 'the x86_64 target deploys to the x86_64 cell');
isnt(cell_lock_path($cell{aarch64}), cell_lock_path($cell{x86_64}),
'the two EL10 targets of one host take different cell locks');
is(cell_lock_path($cell{aarch64}), "$repo/rh10/.aarch64.lock",
'a cell lock sits beside its cell');
}
# A name that is not an EPEL target is refused, so the caller can keep its own error. The
# forcearch and openEuler targets are resolved before this sub is reached.
for my $not (qw(rocky-10-riscv64-xcat openeuler-24.03sp4-x86_64 noble)) {
is(epel_target_profile($not, 'x86_64'), undef, "'$not' is not an EPEL target");
}
done_testing;
+8 -2
View File
@@ -130,11 +130,17 @@ my $grub_spec = slurp($grub_spec_file);
# build does not carry, or efi_uga, makes grub2-mkimage fail.
SKIP: {
my $moddir = '/usr/lib/grub/arm64-efi';
skip 'grub2-mkimage or the arm64-efi grub modules are not installed', 4
unless -d $moddir && system('command -v grub2-mkimage >/dev/null 2>&1') == 0;
# Debian and Ubuntu name the tool grub-mkimage and EL names it grub2-mkimage. The CI
# runner is Ubuntu, so looking only for the EL name skips the checks exactly where the
# suite runs, which measures nothing.
my ($mkimage) = grep { system("command -v $_ >/dev/null 2>&1") == 0 }
qw(grub2-mkimage grub-mkimage);
skip 'no grub2-mkimage or grub-mkimage, or the arm64-efi grub modules are not installed', 4
unless -d $moddir && $mkimage;
skip 'no grub2-mkimage command in the spec', 4 if $cmd eq '';
my $tmp = tempdir(CLEANUP => 1);
my $run = $cmd;
$run =~ s/\Agrub2-mkimage\b/$mkimage/;
$run =~ s/(?<=\s-o\s)\S+/$tmp\/grubaa64.efi/;
is(system("$run >/dev/null 2>&1"), 0, "the spec's grub2-mkimage command succeeds");
my $image = '';
+162
View File
@@ -0,0 +1,162 @@
#!/usr/bin/env bats
# Unit tests for install-grub-arm64-modules.sh. apt-get, dpkg-deb and the grub
# image builder are shell functions here, so no archive is read and the modules
# land only under BATS_TEST_TMPDIR.
setup() {
source "$BATS_TEST_DIRNAME/../install-grub-arm64-modules.sh"
export TMPDIR=$BATS_TEST_TMPDIR
CALLS=$BATS_TEST_TMPDIR/calls
DEST=$BATS_TEST_TMPDIR/dest
DEB_VERSION=2.12-1ubuntu7
TOOL_VERSION=2.12-1ubuntu7.3
DEB_HAS_MODULES=1
}
# Both names, because the loop takes whichever the host has and a developer host
# may carry the real EL one.
grub2-mkimage() {
echo "grub2-mkimage (GRUB) $TOOL_VERSION"
}
grub-mkimage() {
echo "grub-mkimage (GRUB) $TOOL_VERSION"
}
apt-get() {
echo "apt-get $*" >>"$CALLS"
local list
list=$(printf '%s\n' "$@" | sed -nE 's/^Dir::Etc::SourceList=//p')
[ -z "$list" ] || cp "$list" "$BATS_TEST_TMPDIR/sources.list.seen"
case " $* " in
*" download "*)
# apt-get download writes the deb into the working directory.
: >"grub-efi-arm64-bin_${DEB_VERSION}_arm64.deb"
;;
esac
}
# A deb tree with the module directory, the documentation and the prebuilt images
# the real grub-efi-arm64-bin carries.
dpkg-deb() {
echo "dpkg-deb $*" >>"$CALLS"
case $1 in
-f) echo "$DEB_VERSION" ;;
-x)
local out=$3 mod=$3/usr/lib/grub/arm64-efi
if [[ $out != "$BATS_TEST_TMPDIR"/* ]]; then
echo "dpkg-deb -x outside the temporary tree: $out" >&2
return 1
fi
mkdir -p "$out/usr/share/doc/grub-efi-arm64-bin"
: >"$out/usr/share/doc/grub-efi-arm64-bin/copyright"
(( DEB_HAS_MODULES )) || return 0
mkdir -p "$mod/monolithic"
local m
for m in normal linux tftp efinet; do : >"$mod/$m.mod"; done
: >"$mod/kernel.img"
: >"$mod/moddep.lst"
: >"$mod/monolithic/grubnetaa64.efi"
;;
esac
}
leftover_dirs() {
find "$BATS_TEST_TMPDIR" -maxdepth 1 -name 'grub-arm64.*' | wc -l
}
@test "an operand is a usage error" {
run main noble
[ "$status" -eq 2 ]
[[ $output == Usage:* ]]
}
@test "an unknown option is a usage error" {
run main -z
[ "$status" -eq 2 ]
[[ $output == *Usage:* ]]
}
@test "the upstream version of a deb version drops the epoch and the revision" {
[ "$(upstream_version 1:2.12-1ubuntu7.3)" = 2.12 ]
[ "$(upstream_version 2.06-104)" = 2.06 ]
}
@test "the host GRUB version comes from the image builder on PATH" {
[ "$(host_grub_version)" = 2.12 ]
}
@test "no image builder on PATH stops the run before any download" {
host_grub_version() { echo "no grub2-mkimage and no grub-mkimage on PATH" >&2; return 1; }
run main -d "$DEST" -s noble
[ "$status" -eq 1 ]
[ ! -e "$CALLS" ]
}
@test "apt reads the given suite and mirror, with authentication left on" {
run main -d "$DEST" -s jammy -m https://mirror.example/ubuntu-ports
[ "$status" -eq 0 ]
grep -q -- '-o APT::Get::AllowUnauthenticated=false' "$CALLS"
grep -q -- '-o Acquire::AllowInsecureRepositories=false' "$CALLS"
grep -q -- '-o APT::Architectures=arm64' "$CALLS"
grep -q 'apt-get .* update' "$CALLS"
grep -q 'download grub-efi-arm64-bin' "$CALLS"
# The suite and the mirror reach apt through its own sources.list, and the host
# sources and dpkg architectures are never read or changed.
local list
list=$(sed -nE 's/.*-o Dir::Etc::SourceList=([^ ]+).*/\1/p' "$CALLS" | head -1)
[ "$(cat "$BATS_TEST_TMPDIR/sources.list.seen")" = "deb [arch=arm64] https://mirror.example/ubuntu-ports jammy main" ]
[[ $list == "$BATS_TEST_TMPDIR"/grub-arm64.*/sources.list ]]
}
@test "only the module files are installed, and the temporary tree is removed" {
run main -d "$DEST" -s noble
[ "$status" -eq 0 ]
[[ $output == "PASS: 4 arm64-efi modules of GRUB 2.12 in $DEST, from grub-efi-arm64-bin_2.12-1ubuntu7_arm64.deb" ]]
[ -f "$DEST/normal.mod" ]
[ -f "$DEST/kernel.img" ]
[ -f "$DEST/moddep.lst" ]
# Not the documentation, and not the prebuilt images of monolithic/.
[ ! -e "$DEST/usr" ]
[ ! -e "$DEST/monolithic" ]
[ ! -e "$DEST/copyright" ]
[ "$(find "$DEST" -mindepth 1 | wc -l)" -eq 6 ]
[ "$(leftover_dirs)" -eq 0 ]
}
@test "a deb of another GRUB version than the host tool installs nothing" {
DEB_VERSION=2.06-1ubuntu1
run main -d "$DEST" -s noble
[ "$status" -eq 1 ]
[[ $output == *"grub-efi-arm64-bin is GRUB 2.06 and the host image builder is GRUB 2.12"* ]]
[ ! -e "$DEST" ]
[ "$(leftover_dirs)" -eq 0 ]
}
@test "a deb without the module directory installs nothing" {
DEB_HAS_MODULES=0
run main -d "$DEST" -s noble
[ "$status" -eq 1 ]
[[ $output == *"carries no usr/lib/grub/arm64-efi"* ]]
[ ! -e "$DEST" ]
}
@test "a failed apt-get update stops the run before the download" {
apt-get() {
echo "apt-get $*" >>"$CALLS"
case " $* " in *" update "*) return 100 ;; esac
}
run main -d "$DEST" -s noble
[ "$status" -eq 1 ]
[[ $output == *"apt-get update of https://ports.ubuntu.com/ubuntu-ports noble failed"* ]]
! grep -q 'download' "$CALLS"
[ ! -e "$DEST" ]
}
@test "a download that yields no deb is not reported as a success" {
apt-get() { echo "apt-get $*" >>"$CALLS"; }
run main -d "$DEST" -s noble
[ "$status" -eq 1 ]
[[ $output == *"apt downloaded no grub-efi-arm64-bin deb"* ]]
[ ! -e "$DEST" ]
}