2
0
mirror of https://github.com/xcat2/xcat-dep.git synced 2026-09-30 14:55:17 +00:00

Test native repository locks and publisher signature preservation

Exercise mixed repository finalization and changed publisher inputs on x86_64. Check native manifest selection and use File::Slurper in the goconserver fixture.
This commit is contained in:
Vinícius Ferrão
2026-09-29 00:03:57 -03:00
parent 882ca33693
commit 3f3289bc95
6 changed files with 253 additions and 34 deletions
+15 -28
View File
@@ -6,6 +6,7 @@ use File::Basename qw(dirname);
use File::Copy qw(copy);
use File::Path qw(make_path);
use File::Temp qw(tempdir);
use File::Slurper qw(read_text write_text);
use Digest::SHA qw(sha256_hex);
use JSON::PP qw(decode_json);
use Test::More;
@@ -32,23 +33,6 @@ my $payload = "private compiler download fixture\n";
my $hash = sha256_hex($payload);
my $sequence = 0;
sub write_file {
my ($path, $text) = @_;
make_path(dirname($path));
open(my $fh, '>', $path) or die "$path: $!";
print {$fh} $text;
close($fh) or die "$path: $!";
}
sub read_file {
my ($path) = @_;
return '' unless -f $path;
open(my $fh, '<', $path) or die "$path: $!";
my $text = do { local $/; <$fh> };
close($fh) or die "$path: $!";
return $text // '';
}
my $double = <<'DOUBLE';
#!/usr/bin/perl
use strict;
@@ -136,14 +120,15 @@ sub run_case {
my $checkout = "$directory/source";
my $bin = "$directory/bin";
make_path($checkout, $bin);
for my $relative ('MockBuildUtils.pm', 'lib/XCAT/BuildUtils.pm', 'goconserver/gomod/go.mod', 'goconserver/gomod/go.sum') {
for my $relative ('MockBuildUtils.pm', 'lib/XCAT/BuildUtils.pm', 'lib/XCAT/NFSLock.pm', 'goconserver/gomod/go.mod', 'goconserver/gomod/go.sum') {
make_path(dirname("$checkout/$relative"));
copy("$root/$relative", "$checkout/$relative") or die $!;
}
copy($builder, "$checkout/goconserver/mockbuild.pl") or die $!;
write_file("$checkout/goconserver/toolchains/go1.25.12.sha256",
make_path("$checkout/goconserver/toolchains");
write_text("$checkout/goconserver/toolchains/go1.25.12.sha256",
join('', map { "$hash go1.25.12.linux-$_.tar.gz\n" } qw(amd64 ppc64le)));
write_file("$bin/double", $double);
write_text("$bin/double", $double);
chmod 0755, "$bin/double";
symlink('double', "$bin/$_") or die $! for qw(uname bash git wget mock rpm go rpmbuild rpm2cpio cpio);
my @arguments = ('--work-dir', "$directory/work", '--result-dir', "$directory/results",
@@ -173,9 +158,11 @@ sub run_case {
}
waitpid($pid, 0);
my $status = $?;
my @commands = map { decode_json($_) } grep { length } split /\n/, read_file("$directory/commands.jsonl");
return { directory => $directory, status => $status, output => read_file("$directory/output"),
spec => read_file("$directory/work/goconserver.spec"), commands => \@commands };
my $log = -f "$directory/commands.jsonl" ? read_text("$directory/commands.jsonl") : '';
my @commands = map { decode_json($_) } grep { length } split /\n/, $log;
return { directory => $directory, status => $status, output => read_text("$directory/output"),
spec => -f "$directory/work/goconserver.spec" ? read_text("$directory/work/goconserver.spec") : '',
commands => \@commands };
}
sub calls {
@@ -204,7 +191,7 @@ for my $cell (@cells) {
my $config = "openeuler-$version-$arch";
my $case = run_case(os_version => $os_version, arch => $arch);
is($case->{status}, 0, "$config full CLI succeeds with external build doubles") or diag($case->{output});
like(read_file("$case->{directory}/work/mock-deterministic.cfg"), qr/^include\('\/etc\/mock\/\Q$config\E\.cfg'\)/m,
like(read_text("$case->{directory}/work/mock-deterministic.cfg"), qr/^include\('\/etc\/mock\/\Q$config\E\.cfg'\)/m,
"$config builds inside its exact native config");
like($case->{spec}, qr/^Release:\s+4$/m, "$config retains the native empty dist macro");
like($case->{spec}, qr/^BuildArch:\s+\Q$arch\E$/m, "$config retains its native architecture");
@@ -214,7 +201,7 @@ for my $cell (@cells) {
like($case->{spec}, qr/^echo '\Q$hash\E %\{SOURCE3\}' \| sha256sum -c -$/m, "$config verifies the compiler again in RPM prep");
is(scalar @{calls($case, 'mock', '--buildsrpm')}, 1, "$config reaches SRPM construction after verification");
is(scalar @{calls($case, 'mock', '--rebuild')}, 1, "$config reaches native RPM reconstruction");
is(read_file("$case->{directory}/results/goconserver-0.3.3-4.$arch.rpm"), "fixture binary RPM\n", "$config collects the build output");
is(read_text("$case->{directory}/results/goconserver-0.3.3-4.$arch.rpm"), "fixture binary RPM\n", "$config collects the build output");
ok(!-d "$case->{directory}/work/goconserver-src/.git", "$config removes fetched Git metadata from the sources");
build_metadata($case, '2023-11-14T22:13:20Z', $config);
}
@@ -223,7 +210,7 @@ for my $cell (@cells) {
my $case = run_case(config => 'openeuler-22.03sp4-x86_64');
is($case->{status}, 0, 'explicit native target overrides host release detection');
is(scalar @{calls($case, 'bash')}, 0, 'explicit target requires no host release query');
like(read_file("$case->{directory}/work/mock-deterministic.cfg"), qr/openeuler-22\.03sp4-x86_64\.cfg/, 'explicit service pack is retained');
like(read_text("$case->{directory}/work/mock-deterministic.cfg"), qr/openeuler-22\.03sp4-x86_64\.cfg/, 'explicit service pack is retained');
}
for my $options (
@@ -279,7 +266,7 @@ for my $row (
my ($options, $config, $release) = @$row;
my $case = run_case(%$options);
is($case->{status}, 0, "EL$release full CLI succeeds") or diag($case->{output});
like(read_file("$case->{directory}/work/mock-deterministic.cfg"), qr/\Q$config\E\.cfg/, "EL$release retains the EL10 build peer");
like(read_text("$case->{directory}/work/mock-deterministic.cfg"), qr/\Q$config\E\.cfg/, "EL$release retains the EL10 build peer");
like($case->{spec}, qr/^Release:\s+4\.el\Q$release\E$/m, "EL$release retains its target dist suffix");
like($case->{spec}, qr/^BuildRequires:\s+golang$/m, "EL$release retains the distro compiler");
unlike($case->{spec}, qr/^Source3:/m, "EL$release has no native compiler source");
@@ -298,7 +285,7 @@ for my $row (
is_deeply([map { $_->{goarch} } @$go], ['riscv64', 'riscv64'], 'EL cross path selects the target GOARCH');
is(scalar @{calls($case, 'rpmbuild', 'riscv64')}, 1, 'EL cross path packages for the requested target');
is(scalar @{calls($case, 'mock')} + scalar @{calls($case, 'wget')}, 0, 'EL cross path does not invoke native mock or compiler staging');
is(read_file("$case->{directory}/results/goconserver-0.3.3-4.riscv64.rpm"), "fixture binary RPM\n", 'EL cross path collects its package output');
is(read_text("$case->{directory}/results/goconserver-0.3.3-4.riscv64.rpm"), "fixture binary RPM\n", 'EL cross path collects its package output');
}
done_testing();
+55 -2
View File
@@ -10,8 +10,8 @@ use JSON::PP;
use Test::More;
use lib "$RealBin/..", "$RealBin/../lib", "$RealBin/../t/lib";
use MockBuildUtils qw(read_manifest);
use XCAT::BuildUtils qw(capture_command command_exists digest_file read_binary write_binary);
use MockBuildUtils qw(read_manifest sign_and_index_repo);
use XCAT::BuildUtils qw(capture_command command_exists digest_file digest_manifest relative_files read_binary write_binary);
use XCAT::GenesisReleaseTest qw(run_capture dies_like);
use XCAT::NativeInputs qw(load_inputs stage_inputs publisher_trust verify_input validate_outputs);
@@ -239,6 +239,59 @@ for my $case (['publisher-elf', qr/ELF payload/], ['publisher-arch', qr/not a no
ok(!-f $ENV{NATIVE_CALLS}, 'standalone verification runs no downloader or builder');
}
{
my $dest = "$tmp/signing-repo";
make_path($dest);
my $publisher = "$dest/publisher-package-1-1.oe2403.noarch.rpm";
my $child = "$dest/native-child-1-1.oe2403.noarch.rpm";
copy($signed{'publisher-package'}, $publisher) or die $!;
copy($rpm{'native-child'}, $child) or die $!;
my @commands;
my $sequence = 0;
my %options = (
gpg_sign => 1, gpg_home => $homes{build}, gpg_key_name => $keys{build},
gpg_program => '/usr/bin/gpg', source_date_epoch => $epoch,
run => sub {
my ($command) = @_;
push @commands, $command;
my $log = "$tmp/signing-command-" . ++$sequence . '.log';
die read_binary($log) if run_capture($log, '/bin/sh', '-c', $command);
},
);
my $ok = eval { sign_and_index_repo($dest, $plan, %options); 1 };
ok($ok, 'repository signing accepts unchanged publisher input') or die($@);
is(digest_file($publisher), digest_file($signed{'publisher-package'}),
'repository signing preserves the original publisher bytes');
is(run_capture("$tmp/signing-publisher.log", 'rpmkeys', '--dbpath', $plan->{trust_db},
'--checksig', '--verbose', $publisher), 0,
'publisher RPM retains its original trusted signature');
my $build_trust = "$tmp/signing-build-trust";
make_path($build_trust);
is(run_capture("$tmp/signing-build-import.log", 'rpmkeys', '--dbpath', $build_trust,
'--import', "$homes{build}/public.asc"), 0, 'trust the build key in an isolated RPM database');
is(run_capture("$tmp/signing-child.log", 'rpmkeys', '--dbpath', $build_trust,
'--checksig', '--verbose', $child), 0, 'generated RPM verifies with the build key');
like(read_binary("$tmp/signing-child.log"), qr/Signature.*\bOK\b/i,
'generated RPM has a verified signature');
is(run_capture("$tmp/signing-metadata.log", 'gpg', '--homedir', $homes{build},
'--verify', "$dest/repodata/repomd.xml.asc", "$dest/repodata/repomd.xml"), 0,
'repository metadata has a valid build signature');
my $changed = signed_copy($rpm{'publisher-package'}, 'changed-before-signing', 'build');
copy($changed, $publisher) or die $!;
copy($rpm{'native-child'}, $child) or die $!;
isnt(digest_file($publisher), $plan->{nodes}{'publisher-package'}{sha256},
'the changed publisher RPM differs from its pinned input');
my $before = digest_manifest($dest, 'sha256', relative_files($dest));
@commands = ();
dies_like(sub { sign_and_index_repo($dest, $plan, %options) },
qr/\APublisher input changed before signing: \Q$publisher\E\n\z/,
'changed publisher bytes stop repository signing');
is_deeply(\@commands, [], 'changed publisher bytes stop before signing or indexing commands');
is(digest_manifest($dest, 'sha256', relative_files($dest)), $before,
'rejection preserves generated RPMs, publisher RPMs and repository metadata');
}
my @namespace = ('unshare', ($> == 0 ? () : ('--user', '--map-root-user')), '--mount', '--propagation', 'private');
my $can_owner = $host_arch eq 'ppc64le'
&& run_capture("$tmp/mock-loader.log", 'python3', '-c', 'from mockbuild.util import load_config') == 0
+101 -1
View File
@@ -2,6 +2,7 @@ use strict;
use warnings;
use Cwd qw(abs_path cwd);
use File::Basename qw(dirname basename);
use File::Copy qw(copy);
use File::Path qw(make_path);
use File::Spec;
@@ -13,6 +14,7 @@ use Test::More;
use lib "$RealBin/../lib", "$RealBin/../t/lib";
use XCAT::BuildUtils qw(capture_command command_exists digest_file read_binary write_binary);
use XCAT::GenesisReleaseTest qw(run_capture);
use XCAT::NFSLock ();
plan skip_all => 'Linux RPM tools and user namespaces required'
unless $^O eq 'linux' && !grep { !command_exists($_) } qw(rpm rpmkeys rpmbuild createrepo_c unshare gpg gpgconf);
@@ -98,6 +100,14 @@ PERL
make_path("$repo/$cell");
copy($opt{published}{$cell}, "$repo/$cell/python3-scp-0.14.5-1.noarch.rpm") or die $!;
}
my ($held_lock, $lock_path, $lock_before);
if ($opt{hold_cell}) {
my $cell = "$repo/$opt{hold_cell}";
make_path(dirname($cell));
$lock_path = dirname($cell) . '/.' . basename($cell) . '.lock';
$held_lock = XCAT::NFSLock->acquire($lock_path, quiet => 1);
$lock_before = read_binary("$lock_path/metadata");
}
local $ENV{PATH} = "$tmp/bin:$ENV{PATH}";
local $ENV{MOCKBUILD_ALL_MOUNTNS} = 1;
local $ENV{SCP_CALLS} = "$tmp/$name calls.jsonl";
@@ -119,8 +129,11 @@ PERL
'--skip-genesis', '--skip-perl', '--skip-tarball', @options);
my @calls = -f $ENV{SCP_CALLS}
? map { decode_json($_) } split /\n/, read_binary($ENV{SCP_CALLS}) : ();
my $lock_after = $held_lock && -f "$lock_path/metadata" ? read_binary("$lock_path/metadata") : undef;
$held_lock->release if $held_lock;
return {rc => $rc, calls => \@calls, log => read_binary("$tmp/$name.log"), input => $input,
repo => $repo, out => $out, root => $root};
repo => $repo, out => $out, root => $root, lock_path => $lock_path,
lock_before => $lock_before, lock_after => $lock_after};
}
my $selected = scenario('selected');
@@ -253,6 +266,93 @@ my $wrong_cell = scenario('carry-wrong-cell', missing => 1,
isnt($wrong_cell->{rc}, 0, 'a signed package in the EL-shaped path cannot fill a native cell');
like($wrong_cell->{log}, qr/MISSING python3-scp/, 'the native gate reports the package absent from its own cell');
for my $held ('openeuler20.03sp4/x86_64', 'rh20.03sp4/x86_64') {
my $native = $held =~ /^openeuler/;
my $result = scenario($native ? 'native-lock' : 'decoy-lock', missing => 1,
hold_cell => $held, published => {'openeuler20.03sp4/x86_64' => $published},
options => ['--skip-xcat-dep', '--try-unlock-timeout', 0]);
if ($native) {
isnt($result->{rc}, 0, 'the native published cell lock excludes a second publisher');
like($result->{log}, qr/Trying to unlock \Q$result->{lock_path}\E failed/,
'the refusal names the lock beside the native published cell');
is(read_binary("$result->{repo}/openeuler20.03sp4/x86_64/sentinel"), 'previous repository',
'native lock refusal preserves the published repository');
ok(!-d "$result->{out}/mockbuild-all/$target-source-contract",
'native lock refusal precedes carry-over and collection');
} else {
is($result->{rc}, 0, 'an EL-shaped decoy lock does not block native carry-over and deployment')
or diag($result->{log});
ok(-f "$result->{repo}/openeuler20.03sp4/x86_64/python3-scp-0.14.5-1.noarch.rpm",
'the unlocked native cell receives the carried package');
my $metadata = "$result->{repo}/openeuler20.03sp4/x86_64/xcat-dep.repo";
my $config = -f $metadata ? read_binary($metadata) : '';
like($config, qr{^baseurl=.*\/openeuler20\.03sp4/x86_64$}m,
'the native repository configuration names the deployed cell');
}
is_deeply($result->{calls}, [], "$held lock case runs no package builder");
is($result->{lock_after}, $result->{lock_before}, "$held remains held by its original owner");
}
for my $name ('native-only', 'mixed', 'legacy-locked') {
my $root = "$tmp/finalize-$name";
my @native = ("$root/openeuler20.03sp4/x86_64", "$root/openeuler24.03/ppc64le");
make_path(@native);
write_binary("$_/marker", 'native repository') for @native;
my @held_cells = @native;
my ($x, $p) = ("$root/rh9/x86_64", "$root/rh9/ppc64le");
my ($xrpm, $prpm) = ('xCAT-genesis-base-x86_64-2.19.1-1.noarch.rpm',
'xCAT-genesis-base-ppc64-2.19.1-1.noarch.rpm');
if ($name ne 'native-only') {
make_path($x, $p);
copy($published, "$x/$xrpm") or die $!;
copy($published, "$p/$prpm") or die $!;
push @held_cells, $p;
push @held_cells, $x if $name eq 'legacy-locked';
}
my @held;
for my $cell (@held_cells) {
my $path = dirname($cell) . '/.' . basename($cell) . '.lock';
my $lock = XCAT::NFSLock->acquire($path, quiet => 1);
push @held, [$lock, $path, read_binary("$path/metadata")];
}
my $logfile = "$tmp/finalize-$name.log";
my $rc = run_capture($logfile, $^X, $collector, '--finalize-xcat-dep',
'--x86_64-repo', $root, '--ppc64le-repo', $root, '--finalize-arch', 'x86_64',
'--build-timestamp', $epoch, '--try-unlock-timeout', 0, '--no-verify-repo');
my $log = read_binary($logfile);
if ($name eq 'legacy-locked') {
isnt($rc, 0, 'finalization refuses a held legacy destination lock');
like($log, qr{Trying to unlock \Q$root\E/rh9/\.x86_64\.lock failed},
'finalization refuses the same sibling lock as an EL publisher');
ok(!-e "$x/$prpm", 'lock refusal precedes the legacy cross-copy');
ok(!-d "$x/repodata", 'lock refusal precedes legacy reindexing');
} else {
is($rc, 0, "$name finalization ignores held native and unselected cell locks") or diag($log);
if ($name eq 'mixed') {
ok(-f "$x/$prpm", 'selected legacy destination receives its foreign Genesis');
is(-f "$x/$prpm" ? digest_file("$x/$prpm") : undef, digest_file("$p/$prpm"),
'legacy cross-copy preserves the source RPM');
ok(-f "$x/repodata/repomd.xml", 'selected legacy destination is reindexed');
ok(!-e "$p/$xrpm", 'unselected legacy source receives no foreign Genesis');
ok(!-d "$p/repodata", 'unselected legacy source is not reindexed');
} else {
like($log, qr/openEuler.*skipping/, 'native-only finalization explains the skip');
unlike($log, qr/(?:acquired|took-over) repository cell lock/,
'native-only finalization acquires no cell lock');
}
}
for my $native (@native) {
is_deeply([glob("$native/*")], ["$native/marker"], "$name adds no native artifacts");
is(read_binary("$native/marker"), 'native repository', "$name preserves native content");
}
for my $held (@held) {
my ($lock, $path, $before) = @$held;
is(-f "$path/metadata" ? read_binary("$path/metadata") : undef, $before,
"$name preserves the existing owner of $path");
$lock->release;
}
}
my $skipped = scenario('skip-dep', missing => 1, options => ['--skip-xcat-dep', '--dry-run']);
is($skipped->{rc}, 0, 'skipping dependency builds does not require the source RPM');
is_deeply($skipped->{calls}, [], 'skip-dep executes no source action');
+2 -1
View File
@@ -29,9 +29,10 @@ my $epoch = 1788718796;
my $suffix = '.snap202609061819.21';
my $default_release = capture_command('rpm', '--eval', '1%{?dist}');
my $source = "$tmp/source tree";
make_path("$source/xnba/binary");
make_path("$source/xnba/binary", "$source/lib/XCAT");
copy($owner, "$source/xnba/mockbuild.pl") or die $!;
copy("$repo/MockBuildUtils.pm", "$source/MockBuildUtils.pm") or die $!;
copy("$repo/lib/XCAT/NFSLock.pm", "$source/lib/XCAT/NFSLock.pm") or die $!;
copy("$repo/xnba/xnba-undi.spec", "$source/xnba/xnba-undi.spec") or die $!;
copy("$repo/xnba/binary/$_", "$source/xnba/binary/$_") or die $! for qw(xnba.kpxe xnba.efi);
my %specs;
+76 -1
View File
@@ -10,7 +10,7 @@ use lib "$RealBin/..";
use File::Temp qw(tempdir);
use File::Path qw(make_path);
use File::Basename qw(basename);
use File::Slurper qw(write_text);
use File::Slurper qw(read_text write_text);
use MockBuildUtils qw(install_deps_packages install_deps_command missing_perl_modules
required_pkgs version_matches rpm_sigmd5 rpm_version rpm_release rpm_is_signed
rpm_arch rpm_in_cell resolve_mock_cfg
@@ -403,6 +403,81 @@ SPEC
'the refusal names the arch');
}
{
my $tmp = tempdir(CLEANUP => 1);
my ($x, $p) = ("$tmp/x/rh9/x86_64", "$tmp/p/rh9/ppc64le");
my @native = ("$tmp/x/openeuler20.03sp4/x86_64", "$tmp/p/openeuler24.03/ppc64le");
make_path($x, $p, @native);
write_text("$x/xCAT-genesis-base-x86_64-2.19.1-1.noarch.rpm", "x86 genesis\n");
write_text("$p/xCAT-genesis-base-ppc64-2.19.1-1.noarch.rpm", "ppc genesis\n");
write_text("$_/marker", "native repository\n") for @native;
my (@signed, @reindexed);
my $ok = eval {
quiet { finalize_xcat_dep("$tmp/x", "$tmp/p",
sign => sub { push @signed, $_[0] },
reindex => sub { push @reindexed, $_[0] }) };
1;
};
ok($ok, 'mixed roots finalize their legacy cells without native peer requirements') or diag($@);
is(-f "$x/xCAT-genesis-base-ppc64-2.19.1-1.noarch.rpm"
? read_text("$x/xCAT-genesis-base-ppc64-2.19.1-1.noarch.rpm") : undef, "ppc genesis\n",
'the legacy x86 cell receives its foreign Genesis');
is(-f "$p/xCAT-genesis-base-x86_64-2.19.1-1.noarch.rpm"
? read_text("$p/xCAT-genesis-base-x86_64-2.19.1-1.noarch.rpm") : undef, "x86 genesis\n",
'the legacy ppc cell receives its foreign Genesis');
is_deeply([sort @signed], [sort { $a cmp $b } ("$x/xCAT-genesis-base-ppc64-2.19.1-1.noarch.rpm",
"$p/xCAT-genesis-base-x86_64-2.19.1-1.noarch.rpm")], 'only legacy copies are signed');
is_deeply([sort @reindexed], [sort { $a cmp $b } ($x, $p)], 'only legacy cells are indexed');
for my $native (@native) {
is_deeply([glob("$native/*")], ["$native/marker"], 'finalize adds no native artifacts');
is(read_text("$native/marker"), "native repository\n", 'finalize preserves native content');
}
}
{
my $tmp = tempdir(CLEANUP => 1);
my @native = ("$tmp/x/openeuler20.03sp4/x86_64", "$tmp/p/openeuler24.03/ppc64le");
make_path(@native);
write_text("$_/marker", "native repository\n") for @native;
my (@signed, @reindexed);
my $ok = eval {
quiet { finalize_xcat_dep("$tmp/x", "$tmp/p", only => ['x86_64'],
sign => sub { push @signed, $_[0] },
reindex => sub { push @reindexed, $_[0] }) };
1;
};
ok($ok, 'native-only roots require no legacy Genesis finalization') or diag($@);
is_deeply(\@signed, [], 'native-only finalization signs nothing');
is_deeply(\@reindexed, [], 'native-only finalization indexes nothing');
for my $native (@native) {
is_deeply([glob("$native/*")], ["$native/marker"], 'native-only finalization adds no artifacts');
is(read_text("$native/marker"), "native repository\n", 'native-only finalization preserves content');
}
my $bad = eval { quiet { finalize_xcat_dep("$tmp/x", "$tmp/p", only => ['riscv64']) }; 1 };
ok(!$bad, 'native-only roots still reject an unsupported finalization architecture');
like($@, qr/no cross-arch genesis for arch 'riscv64'/, 'native-only validation names the bad architecture');
}
for my $legacy ('x86-only', 'ppc-only', 'missing-genesis') {
my $tmp = tempdir(CLEANUP => 1);
make_path("$tmp/x/openeuler20.03sp4/x86_64", "$tmp/p/openeuler24.03/ppc64le");
make_path("$tmp/x/rh9/x86_64") unless $legacy eq 'ppc-only';
make_path("$tmp/p/rh9/ppc64le") unless $legacy eq 'x86-only';
my (@signed, @reindexed);
my $ok = eval {
quiet { finalize_xcat_dep("$tmp/x", "$tmp/p",
sign => sub { push @signed, $_[0] },
reindex => sub { push @reindexed, $_[0] }) };
1;
};
ok(!$ok, "$legacy legacy input remains fatal in mixed roots");
my $expected = $legacy eq 'x86-only' ? qr/no ppc64le peer repo/
: $legacy eq 'ppc-only' ? qr/no x86_64 peer repo/ : qr/no x86_64 xCAT-genesis-base/;
like($@, $expected, "$legacy reports the missing legacy input");
is_deeply(\@signed, [], "$legacy signs nothing");
is_deeply(\@reindexed, [], "$legacy indexes nothing");
}
# ---- restamp_release_line: CD --build-number Release stamping (PR #62 review point 1) ----------
# A fresh stamp is appended after the Release token, preserving any %{?dist} macro.
{
+4 -1
View File
@@ -5,8 +5,9 @@ use FindBin qw($RealBin);
use lib "$RealBin/..";
use Test::More;
use MockBuildUtils qw(openeuler_build_target openeuler_repo_subdir install_deps_command
install_deps_packages derive_target_from_repo_path);
install_deps_packages derive_target_from_repo_path read_manifest);
my %manifest = read_manifest("$RealBin/../packages-manifest.conf");
my @cells = (
['20.03sp4', '20.03-LTS-SP4', '20.03LTS_SP4', 'x86_64'],
['22.03sp4', '22.03-LTS-SP4', '22.03LTS_SP4', 'x86_64'],
@@ -20,6 +21,8 @@ for my $cell (@cells) {
my ($base, $sp) = $version =~ /^(\d+\.\d+)(?:sp(\d+))?$/;
my $native_version = "$base (LTS" . (defined($sp) ? "-SP$sp" : '') . ')';
my $target = "openeuler-$version-$arch";
ok(-f "$RealBin/../mock-configs/$target.cfg", "$target has a native mock config");
ok(exists $manifest{$target}{goconserver}, "$target has a native package manifest");
is(openeuler_build_target({ID => 'openEuler', VERSION => $native_version}, $arch), $target,
"$target retains the native service pack");
is(openeuler_repo_subdir($target), "openeuler$version/$arch", "$target preserves repository provenance");