Files
webmin/t/software-apt.t
Ilia Ross e695fbd0c7 Add APT package hold management to Package Updates
- Add an APT-only “Held updates” view while keeping held packages excluded from normal and scheduled updates.

- Allow administrators to hold or unhold packages from package details.

- Allow explicitly selected held packages to be updated once, then restore all existing package holds.

- Preserve configured `aptitude` behavior for regular installs while using `apt-get` for the held-package override.

Fixes #2689
2026-08-14 03:43:50 +02:00

191 lines
5.7 KiB
Perl

#!/usr/local/bin/perl
use strict;
use warnings;
use Test::More;
use File::Basename qw(dirname);
use File::Spec;
use Cwd qw(abs_path);
our %config;
our $apt_get_command;
my $root = abs_path(File::Spec->catdir(dirname(__FILE__), '..'));
chdir($root) or die "chdir($root): $!";
do './software/apt-lib.pl' or die $@ || $!;
is(strip_apt_package_arch('libtinfo6:amd64'), 'libtinfo6',
'strips native Debian architecture suffix');
is(strip_apt_package_arch('libgomp1:i386'), 'libgomp1',
'strips foreign Debian architecture suffix');
is(strip_apt_package_arch('ncurses-base'), 'ncurses-base',
'leaves unqualified package names unchanged');
{
no warnings qw(once redefine);
local *backquote_command = sub {
return "Inst libtinfo6:amd64 [6.3-2ubuntu0.1] ".
"(6.3-2ubuntu0.2 Ubuntu:22.04/jammy-updates [amd64])\n";
};
local *clean_language = sub { };
local *reset_environment = sub { };
my @ops = update_system_operations('libtinfo6');
is($ops[0]->{'name'}, 'libtinfo6',
'normalizes package names from simulated APT operations');
}
{
no warnings qw(once redefine);
my $apt_output = "Setting up libtinfo6:amd64 (6.3-2ubuntu0.2) ...\n";
my $yes_input = "";
my $executed_command = "";
my @reheld;
local *additional_log = sub { };
local *backquote_logged = sub { return ""; };
local *clean_language = sub { };
local *html_escape = sub { return $_[0]; };
local *reset_environment = sub { };
local *list_update_system_holds = sub {
return ('libtinfo6:amd64', 'held-dependency:i386');
};
local *update_system_hold = sub {
my ($packages, $hold) = @_;
@reheld = @$packages if ($hold);
return undef;
};
local *text = sub { return $_[0]; };
local *transname = sub { return "/tmp/software-apt-test-yes"; };
local *open_tempfile = sub {
my ($fh) = @_;
no strict 'refs';
open(ref($fh) ? $fh : \*{$fh}, ">", \$yes_input)
or die "open temp input: $!";
};
local *print_tempfile = sub {
my ($fh, @text) = @_;
no strict 'refs';
my $handle = ref($fh) ? $fh : \*{$fh};
print $handle @text;
};
local *close_tempfile = sub {
my ($fh) = @_;
no strict 'refs';
close(ref($fh) ? $fh : \*{$fh});
};
local *open_execute_command = sub {
my ($fh, $command) = @_;
$executed_command = $command;
no strict 'refs';
open(ref($fh) ? $fh : \*{$fh}, "<", \$apt_output)
or die "open simulated apt output: $!";
};
local $config{'package_system'} = 'debian';
local $apt_get_command = 'aptitude';
my $printed = "";
open(my $stdout, ">", \$printed) or die "open captured stdout: $!";
local *STDOUT = $stdout;
my @installed = update_system_install(
'libtinfo6', undef, 1, '--allow-change-held-packages');
is_deeply(\@installed, [ 'libtinfo6' ],
'normalizes package names returned by apt install output');
like($executed_command, qr/apt-get -y --allow-change-held-packages install/,
'uses apt-get for the held-package override even in aptitude mode');
is_deeply(\@reheld, [ 'libtinfo6:amd64', 'held-dependency:i386' ],
'restores all exact holds after explicitly updating a held package');
$executed_command = "";
@reheld = ( );
update_system_install('libtinfo6', undef, 1);
like($executed_command, qr/^aptitude -y install/,
'continues using configured aptitude mode for regular installs');
is_deeply(\@reheld, [ ], 'does not reapply holds after a regular install');
}
{
no warnings qw(once redefine);
local *clean_language = sub { };
local *reset_environment = sub { };
local *has_command = sub {
return $_[0] eq 'aptitude' || $_[0] eq 'apt-mark';
};
local *open_execute_command = sub {
my ($fh, $command) = @_;
my $output = $command =~ /^dpkg / ?
"alpha hold\ndelta:amd64 hold\n" :
$command =~ /^aptitude / ?
".h beta 1.0 installed\n" :
$command =~ /^apt-mark / ?
"gamma\ndelta:amd64\n" : "";
no strict 'refs';
open(ref($fh) ? $fh : \*{$fh}, '<', \$output)
or die "open simulated holds: $!";
};
is_deeply([ list_update_system_holds() ],
[ qw(alpha beta delta:amd64 gamma) ],
'combines held packages without discarding architecture qualifiers');
}
{
no warnings qw(once redefine);
my $apt_output =
"Listing...\n".
"held-pkg/stable 2.0 amd64 [upgradable from: 1.0]\n".
"regular-pkg/stable 3.0 amd64 [upgradable from: 2.0]\n";
local *clean_language = sub { };
local *reset_environment = sub { };
local *execute_command = sub { return 0; };
local *list_update_system_holds = sub { return ('held-pkg'); };
local *has_command = sub { return $_[0] eq 'apt'; };
local *open_execute_command = sub {
my ($fh, $command) = @_;
my $output = $command =~ /^apt list / ? $apt_output : "";
no strict 'refs';
open(ref($fh) ? $fh : \*{$fh}, '<', \$output)
or die "open simulated updates: $!";
};
my @normal = update_system_updates(0);
is_deeply([ map { $_->{'name'} } @normal ], [ 'regular-pkg' ],
'default APT updates still exclude held packages');
my @with_holds = update_system_updates(1);
is_deeply([ map { $_->{'name'} } @with_holds ],
[ 'held-pkg', 'regular-pkg' ],
'held-update query includes regular and held packages');
ok($with_holds[0]->{'held'}, 'marks the held update');
ok(!$with_holds[1]->{'held'}, 'does not mark a regular update as held');
}
{
no warnings qw(once redefine);
my $command;
local *has_command = sub { return '/usr/bin/apt-mark'; };
local *unique = sub {
my %seen;
return grep { !$seen{$_}++ } @_;
};
local *trim = sub {
my ($value) = @_;
$value =~ s/^\s+|\s+$//g;
return $value;
};
local *clean_language = sub { };
local *reset_environment = sub { };
local *execute_command_logged = sub {
my ($cmd, undef, $stdout) = @_;
$command = $cmd;
$$stdout = "";
return 0;
};
is(update_system_hold([ 'webmin-virtual-server', 'webmin-virtual-server' ], 1),
undef, 'holds packages successfully');
is($command, 'apt-mark hold webmin\-virtual\-server',
'builds a quoted apt-mark hold command without duplicates');
}
done_testing();