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

test: simplify openEuler native fixtures

This commit is contained in:
Vinícius Ferrão
2026-09-22 23:09:27 -03:00
parent 724602f485
commit a41b0bd684
11 changed files with 201 additions and 154 deletions
@@ -7,13 +7,14 @@ use File::Temp qw(tempdir);
use FindBin qw($RealBin);
use Test::More;
use lib "$RealBin/../lib", "$RealBin/lib";
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);
plan skip_all => 'Linux RPM repository tools required'
unless $^O eq 'linux' && !grep { !command_exists($_) } qw(git rpm rpmbuild createrepo_c unshare);
unless $^O eq 'linux' && !grep { !command_exists($_) } qw(git rpm rpmbuild createrepo_c unshare gpg gpgconf rpmsign);
my $parent_pid = $$;
my $tmp = tempdir(CLEANUP => 1);
my @namespace = $> == 0 ? () : ('unshare', '--user', '--map-root-user');
plan skip_all => 'An unprivileged user namespace is required for the collector root check'
@@ -41,9 +42,22 @@ mkdir -p %{buildroot}/usr/share/provenance-fixture
SPEC
is(run_capture("$tmp/rpm-build.log", 'rpmbuild', '--quiet', '-bb', '--define', "_topdir $top",
"$top/SPECS/provenance-fixture.spec"), 0, 'build an isolated RPM fixture')
or BAIL_OUT(read_binary("$tmp/rpm-build.log"));
or die(read_binary("$tmp/rpm-build.log"));
my $fixture = "$top/RPMS/noarch/provenance-fixture-1-1.noarch.rpm";
my $fixture_hash = digest_file($fixture);
my $key_home = "$tmp/gnupg";
make_path($key_home);
chmod 0700, $key_home;
my $key_name = 'provenance@example.invalid';
die read_binary("$tmp/key.log") if run_capture("$tmp/key.log", 'gpg', '--homedir', $key_home,
'--batch', '--pinentry-mode', 'loopback', '--passphrase', '', '--quick-generate-key',
$key_name, 'rsa2048', 'sign', '0');
END {
local $?;
run_capture("$tmp/key-cleanup.log", 'gpgconf', '--homedir', $key_home, '--kill', 'gpg-agent')
if defined($parent_pid) && $$ == $parent_pid && defined($key_home) && -d $key_home;
}
my $payload_hash = capture_command('rpm', '-qp', '--qf', '%{SIGMD5}', $fixture);
for my $case (qw(checkout export missing empty)) {
my $root = "$tmp/$case source";
@@ -81,7 +95,8 @@ for my $case (qw(checkout export missing empty)) {
'--repo-dep', $repo, '--run-id', 'provenance', '--build-timestamp', $epoch,
'--skip-build', '--skip-genesis', '--skip-xcat-dep', '--skip-perl',
'--skip-createrepo', '--skip-tarball', '--no-verify-repo',
'--collect-dir', "$top/RPMS/noarch");
'--collect-dir', "$top/RPMS/noarch",
'--gpg-sign', '--gpg-home', $key_home, '--gpg-key-name', $key_name);
is($status, 0, "$case $target full collector succeeds") or diag(read_binary($log));
my $subdir = $target =~ /^openeuler/ ? "openeuler24.03sp3/$arch" : "rh10/$arch";
my $metadata_path = "$repo/$subdir/buildinfo.txt";
@@ -92,8 +107,8 @@ for my $case (qw(checkout export missing empty)) {
is($metadata{COMMIT_ID}, substr($expected, 0, 7), "$case $target preserves the short identity contract");
is($metadata{SOURCE_DATE_EPOCH}, "$epoch", "$case $target retains the explicit epoch");
is($metadata{TARGET}, $subdir, "$case $target retains the target repository path");
is(digest_file("$repo/$subdir/provenance-fixture-1-1.noarch.rpm"), $fixture_hash,
"$case $target collection preserves the RPM bytes");
is(capture_command('rpm', '-qp', '--qf', '%{SIGMD5}', "$repo/$subdir/provenance-fixture-1-1.noarch.rpm"), $payload_hash,
"$case $target signing preserves the RPM payload");
}
}
+23
View File
@@ -0,0 +1,23 @@
import configparser
import json
from pathlib import Path
import shutil
import sys
import tempfile
from mockbuild.config import load_config
source = Path(sys.argv[1]).resolve()
with tempfile.TemporaryDirectory() as directory:
config_path = Path(directory)
(config_path / 'templates').mkdir()
for parent in ('openeuler-20.03-sp4.tpl', 'openeuler-22.03-sp4.tpl', 'openeuler-24.03.tpl'):
shutil.copyfile(Path('/etc/mock/templates') / parent, config_path / 'templates' / parent)
shutil.copyfile(source / 'templates/openeuler-lts-xcat.tpl', config_path / 'templates/openeuler-lts-xcat.tpl')
result = {}
for wrapper in sorted(source.glob('openeuler-*.cfg')):
config = load_config(str(config_path), str(wrapper))
repos = configparser.ConfigParser(interpolation=None)
repos.read_string(config['dnf.conf'])
result[wrapper.stem] = {key: config[key] for key in ('root', 'target_arch', 'legal_host_arches', 'releasever', 'dist', 'use_bootstrap_image')}
result[wrapper.stem]['repos'] = {section: dict(repos[section]) for section in repos.sections()}
print(json.dumps(result))
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/python3
import json, os, pathlib, shutil, sys
import mockbuild
from mockbuild.util import load_config
args = sys.argv[1:]
call = {'mock': args}
def value(name): return args[args.index(name)+1]
if '--rebuild' in args or '--buildsrpm' in args:
load_config('/etc/mock', value('-r'), None, 'native-contract',
str(pathlib.Path(mockbuild.__file__).parent))
call['config_rc'] = 0
if '--rebuild' in args:
name = pathlib.Path(value('--rebuild')).name.split('-1-1.oe2403')[0]
call['name'] = name
if '--buildsrpm' in args:
call['spec'] = pathlib.Path(value('--spec')).read_text()
with open(os.environ['NATIVE_CALLS'], 'a') as f: f.write(json.dumps(call) + '\n')
if '--buildsrpm' in args:
dest = pathlib.Path(value('--resultdir')); dest.mkdir(parents=True, exist_ok=True)
source = json.loads(pathlib.Path(os.environ['NATIVE_OUTPUTS']).read_text())['native-leaf'][1]
shutil.copyfile(source, dest / pathlib.Path(source).name)
sys.exit(0)
if '--rebuild' not in args: sys.exit(0)
if name == os.environ.get('NATIVE_FAIL'): sys.exit(42)
dest = pathlib.Path(value('--resultdir')); dest.mkdir(parents=True, exist_ok=True)
if name == os.environ.get('NATIVE_EMPTY'): sys.exit(0)
fixtures = json.loads(pathlib.Path(os.environ['NATIVE_OUTPUTS']).read_text())
for source in fixtures[name]: shutil.copyfile(source, dest / pathlib.Path(source).name)
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env perl
use strict;
use warnings;
use File::Copy qw(copy);
use JSON::PP qw(decode_json encode_json);
open(my $input, '<', $ENV{NATIVE_DOWNLOADS}) or die $!;
my $downloads = decode_json(do { local $/; <$input> });
close($input) or die $!;
my ($output) = grep { $ARGV[$_] eq '-O' } 0 .. $#ARGV - 1;
die 'wget fixture requires -O' unless defined($output);
open(my $trace, '>>', $ENV{NATIVE_CALLS}) or die $!;
print {$trace} encode_json({wget => $ARGV[-1]}) . "\n" or die $!;
close($trace) or die $!;
copy($downloads->{$ARGV[-1]}, $ARGV[$output + 1]) or die $!;
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Digest::SHA qw(sha256_hex);
use File::Basename qw(basename);
use File::Copy qw(copy);
use File::Path qw(make_path);
use JSON::PP qw(encode_json);
sub option {
my ($name) = @_;
for my $i (0 .. $#ARGV - 1) { return $ARGV[$i + 1] if $ARGV[$i] eq $name; }
return;
}
sub contents {
open(my $file, '<', $_[0]) or die $!;
binmode($file);
return do { local $/; <$file> };
}
my %entry = (argv => \@ARGV);
my $config = option('-r');
$entry{config} = contents($config) if defined($config) && -f $config;
$entry{spec} = contents(option('--spec')) if defined(option('--spec'));
if (my $source = option('--rebuild')) {
$entry{source} = $source;
$entry{sha256} = sha256_hex(contents($source));
}
open(my $trace, '>>', $ENV{SCP_CALLS}) or die $!;
print {$trace} encode_json(\%entry) . "\n" or die $!;
close($trace) or die $!;
exit 0 if grep { /^--scrub=/ } @ARGV;
if (grep { $_ eq '--buildsrpm' } @ARGV) {
my $dest = option('--resultdir');
make_path($dest);
copy($ENV{SCP_FIXTURE_SOURCE}, "$dest/python3-scp-0.14.5-1.src.rpm") or die $!;
exit 0;
}
if ($ENV{SCP_MUTATE_SOURCE}) {
open(my $source, '>>', $ENV{SCP_MUTATE_SOURCE}) or die $!;
print {$source} 'changed after staging' or die $!;
close($source) or die $!;
}
exit 43 if ($ENV{SCP_BUILD_STATUS} // '43') ne '0';
if (($ENV{SCP_EMPTY_OUTPUT} // '') ne '1') {
my $dest = option('--resultdir');
make_path($dest);
for my $key (qw(SCP_FIXTURE_BINARY SCP_FIXTURE_SOURCE)) {
copy($ENV{$key}, "$dest/" . basename($ENV{$key})) or die $!;
}
}
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin qw($RealBin);
use JSON::PP qw(decode_json);
use Test::More;
plan skip_all => 'native Mock Python library and templates required'
if system('python3 -c "import mockbuild.config" >/dev/null 2>&1') != 0
|| !-f '/etc/mock/templates/openeuler-24.03.tpl';
my @cells = (
['20.03sp4', '20.03-LTS-SP4', '20.03LTS_SP4', 'x86_64'],
['22.03sp4', '22.03-LTS-SP4', '22.03LTS_SP4', 'x86_64'],
['24.03sp1', '24.03-LTS-SP1', '24.03LTS_SP1', 'x86_64'],
['24.03sp3', '24.03-LTS-SP3', '24.03LTS_SP3', 'x86_64'],
['24.03sp4', '24.03-LTS-SP4', '24.03LTS_SP4', 'x86_64'],
['24.03', '24.03-LTS', '24.03LTS', 'ppc64le'],
);
open(my $pipe, '-|', 'python3', "$RealBin/fixtures/mock-configs.py", "$RealBin/../mock-configs") or die $!;
my $json = do {local $/; <$pipe>};
close($pipe) or die "native mock config loader failed: $?";
my $configs = decode_json($json);
for my $cell (@cells) {
my ($version, $release, $releasever, $arch) = @$cell;
my $target = "openeuler-$version-$arch";
my $config = $configs->{$target};
is($config->{root}, $target, "$target selects its own buildroot");
is($config->{target_arch}, $arch, "$target selects its native architecture");
is_deeply($config->{legal_host_arches}, [$arch], "$target requires a native host");
is($config->{releasever}, $releasever, "$target retains the release package convention");
is($config->{dist}, '', "$target retains the native empty dist macro");
ok(!$config->{use_bootstrap_image}, "$target constructs its bootstrap from signed native RPMs");
my $repos = $config->{repos};
my @names = $arch eq 'ppc64le' ? ('OS') : ('OS', 'everything', 'update');
is_deeply([sort grep {$_ ne 'main'} keys %$repos], [sort @names], "$target selects only published native repositories");
is($repos->{main}{gpgcheck}, '1', "$target requires native package signatures");
my $base = "https://repo.openeuler.org/openEuler-$release";
is_deeply([map {$repos->{$_}{baseurl}} @names], [map {"$base/$_/$arch/"} @names], "$target pins repository URLs to its exact release");
is_deeply([map {$repos->{$_}{gpgkey}} @names], [map {"$base/OS/$arch/RPM-GPG-KEY-openEuler"} @names], "$target uses the release signing key");
ok(!grep({$repos->{$_}{gpgcheck} ne '1' || $repos->{$_}{skip_if_unavailable} ne '0'} @names), "$target fails on unsigned packages or unavailable repositories");
}
done_testing();
@@ -9,7 +9,7 @@ use FindBin qw($RealBin);
use JSON::PP;
use Test::More;
use lib "$RealBin/..", "$RealBin/../lib", "$RealBin/lib";
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 XCAT::GenesisReleaseTest qw(run_capture dies_like);
@@ -22,6 +22,7 @@ plan skip_all => 'Set XCAT_TEST_BUILD_USER to an unprivileged fixture builder' i
my $build_uid = $> == 0 ? getpwnam($build_user) : $>;
plan skip_all => 'The fixture builder must be unprivileged' unless defined($build_uid) && $build_uid != 0;
my @rpm_user = $> == 0 ? ('runuser', '-u', $build_user, '--') : ();
my $parent_pid = $$;
my $tmp = tempdir(CLEANUP => !$ENV{XCAT_TEST_KEEP});
diag("native input fixtures: $tmp");
my $repo = abs_path("$RealBin/..");
@@ -32,7 +33,7 @@ my $epoch = 1788718796;
my $host_arch = capture_command('uname', '-m');
my %manifest = read_manifest("$repo/packages-manifest.conf");
my $production_plan = eval { load_inputs($repo, $manifest{$target}); };
ok($production_plan, 'the shipped full POWER manifest has an executable native input plan') or BAIL_OUT($@);
ok($production_plan, 'the shipped full POWER manifest has an executable native input plan') or die($@);
is($production_plan->{nodes}{'xCAT-genesis-base'}{build_uid}, 0, 'the shipped Genesis owner declares its root assembly exception');
my %homes;
my %keys;
@@ -46,14 +47,15 @@ for my $key (qw(publisher build foreign)) {
chmod 0700, $home;
is(run_capture("$tmp/key-$key.log", 'gpg', '--homedir', $home, '--batch', '--pinentry-mode', 'loopback',
'--passphrase', '', '--quick-generate-key', "$key\@example.invalid", 'rsa2048', 'sign', '0'), 0,
"create private $key key") or BAIL_OUT(read_binary("$tmp/key-$key.log"));
"create private $key key") or die(read_binary("$tmp/key-$key.log"));
my $listing = capture_command('gpg', '--homedir', $home, '--with-colons', '--list-keys');
($keys{$key}) = $listing =~ /^fpr:::::::::([0-9A-F]+):/m;
write_binary("$home/public.asc", capture_command('gpg', '--homedir', $home, '--armor', '--export', $keys{$key}));
}
END {
local $?;
for my $home (values %homes) {
run_capture("$home/cleanup.log", 'gpgconf', '--homedir', $home, '--kill', 'gpg-agent') if -d $home;
run_capture("$home/cleanup.log", 'gpgconf', '--homedir', $home, '--kill', 'gpg-agent') if defined($parent_pid) && $$ == $parent_pid && -d $home;
}
}
@@ -84,7 +86,7 @@ SPEC
write_binary("$tmp/rpmbuild/SPECS/$name.spec", $spec);
is(run_capture("$tmp/fixture-$name.log", @rpm_user, 'rpmbuild', '-ba', '--define', "_topdir $tmp/rpmbuild",
"$tmp/rpmbuild/SPECS/$name.spec"), 0, "build real $name fixture with nonroot check")
or BAIL_OUT(read_binary("$tmp/fixture-$name.log"));
or die(read_binary("$tmp/fixture-$name.log"));
$rpm{$name} = "$tmp/rpmbuild/RPMS/$arch/$name-1-1.oe2403.$arch.rpm";
$rpm{"$name-src"} = "$tmp/rpmbuild/SRPMS/$name-1-1.oe2403.src.rpm";
}
@@ -96,7 +98,7 @@ sub signed_copy {
local $ENV{GNUPGHOME} = $homes{$key};
is(run_capture("$tmp/sign-$name.log", 'rpmsign', '--define', "_gpg_name $keys{$key}",
'--define', '__gpg /usr/bin/gpg', '--addsign', $dest), 0, "sign $name with $key key")
or BAIL_OUT(read_binary("$tmp/sign-$name.log"));
or die(read_binary("$tmp/sign-$name.log"));
return $dest;
}
my %signed;
@@ -105,50 +107,8 @@ for my $name (qw(native-leaf-src native-child-src publisher-package publisher-el
}
my $foreign = signed_copy($rpm{'native-leaf-src'}, 'foreign-source', 'foreign');
write_binary("$tmp/bin/wget", <<'PY');
#!/usr/bin/python3
import json, os, pathlib, shutil, sys
args = sys.argv[1:]
source = json.loads(pathlib.Path(os.environ['NATIVE_DOWNLOADS']).read_text())[args[-1]]
with open(os.environ['NATIVE_CALLS'], 'a') as f: f.write(json.dumps({'wget': args[-1]}) + '\n')
shutil.copyfile(source, args[args.index('-O')+1])
PY
write_binary("$tmp/bin/mock", <<'PY');
#!/usr/bin/python3
import json, os, pathlib, shutil, subprocess, sys
args = sys.argv[1:]
call = {'mock': args}
def value(name): return args[args.index(name)+1]
if '--rebuild' in args or '--buildsrpm' in args:
loader = '''import json, pathlib, sys, mockbuild
from mockbuild.util import load_config
config = load_config('/etc/mock', sys.argv[1], None, 'native-contract', str(pathlib.Path(mockbuild.__file__).parent))
print(json.dumps({'uid': config['chrootuid'], 'dnf': config['dnf.conf']}))
'''
config = subprocess.run([sys.executable, '-c', loader, value('-r')],
text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
call['config_rc'] = config.returncode
if config.returncode:
print(config.stdout)
sys.exit(config.returncode)
if '--rebuild' in args:
name = pathlib.Path(value('--rebuild')).name.split('-1-1.oe2403')[0]
call['name'] = name
if '--buildsrpm' in args:
call['spec'] = pathlib.Path(value('--spec')).read_text()
with open(os.environ['NATIVE_CALLS'], 'a') as f: f.write(json.dumps(call) + '\n')
if '--buildsrpm' in args:
dest = pathlib.Path(value('--resultdir')); dest.mkdir(parents=True, exist_ok=True)
source = json.loads(pathlib.Path(os.environ['NATIVE_OUTPUTS']).read_text())['native-leaf'][1]
shutil.copyfile(source, dest / pathlib.Path(source).name)
sys.exit(0)
if '--rebuild' not in args: sys.exit(0)
if name == os.environ.get('NATIVE_FAIL'): sys.exit(42)
dest = pathlib.Path(value('--resultdir')); dest.mkdir(parents=True, exist_ok=True)
if name == os.environ.get('NATIVE_EMPTY'): sys.exit(0)
fixtures = json.loads(pathlib.Path(os.environ['NATIVE_OUTPUTS']).read_text())
for source in fixtures[name]: shutil.copyfile(source, dest / pathlib.Path(source).name)
PY
copy("$RealBin/fixtures/power-wget.pl", "$tmp/bin/wget") or die $!;
copy("$RealBin/fixtures/power-mock.py", "$tmp/bin/mock") or die $!;
chmod 0755, "$tmp/bin/wget", "$tmp/bin/mock";
local $ENV{PATH} = "$tmp/bin:$ENV{PATH}";
local $ENV{NATIVE_DOWNLOADS} = "$tmp/downloads.json";
+8 -38
View File
@@ -10,12 +10,13 @@ use FindBin qw($RealBin);
use JSON::PP qw(decode_json);
use Test::More;
use lib "$RealBin/../lib", "$RealBin/lib";
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);
plan skip_all => 'Linux RPM tools and user namespaces required'
unless $^O eq 'linux' && !grep { !command_exists($_) } qw(rpm rpmkeys rpmbuild createrepo_c unshare python3 gpg gpgconf);
unless $^O eq 'linux' && !grep { !command_exists($_) } qw(rpm rpmkeys rpmbuild createrepo_c unshare gpg gpgconf);
my $parent_pid = $$;
my $tmp = tempdir(CLEANUP => 1);
my @namespace = $> == 0 ? () : ('unshare', '--user', '--map-root-user');
plan skip_all => 'User namespace unavailable for the collector root check'
@@ -40,10 +41,11 @@ if ($ENV{XCAT_TEST_GENESIS_SIGNING_ONLY}) {
is(run_capture("$tmp/key.log", 'gpg', '--homedir', $key_home, '--batch', '--pinentry-mode', 'loopback',
'--passphrase', '', '--quick-generate-key', $key_name, 'rsa2048', 'sign', '0'), 0,
'create a private ephemeral signing identity for the repository gate')
or BAIL_OUT(read_binary("$tmp/key.log"));
or die(read_binary("$tmp/key.log"));
END {
local $?;
run_capture("$tmp/key-cleanup.log", 'gpgconf', '--homedir', $key_home, '--kill', 'gpg-agent')
if defined($key_home) && -d $key_home;
if defined($parent_pid) && $$ == $parent_pid && defined($key_home) && -d $key_home;
}
write_binary("$tmp/fixture/SPECS/python3-scp.spec", <<'SPEC');
Name: python3-scp
@@ -62,40 +64,8 @@ printf 'fixture\n' > %{buildroot}/usr/share/scp-contract/payload
SPEC
is(run_capture("$tmp/fixture.log", 'rpmbuild', '--quiet', '-ba', '--define', "_topdir $tmp/fixture",
"$tmp/fixture/SPECS/python3-scp.spec"), 0, 'build real RPM fixtures for the command boundary')
or BAIL_OUT(read_binary("$tmp/fixture.log"));
write_binary("$tmp/bin/mock", <<'PYTHON');
#!/usr/bin/python3
import hashlib, json, os, pathlib, shutil, sys
args = sys.argv[1:]
entry = {'argv': args}
def option(name):
return args[args.index(name) + 1]
if '-r' in args and pathlib.Path(option('-r')).is_file():
entry['config'] = pathlib.Path(option('-r')).read_text()
if '--spec' in args:
entry['spec'] = pathlib.Path(option('--spec')).read_text()
if '--rebuild' in args:
src = pathlib.Path(option('--rebuild'))
entry['source'] = str(src)
entry['sha256'] = hashlib.sha256(src.read_bytes()).hexdigest()
with open(os.environ['SCP_CALLS'], 'a') as stream:
stream.write(json.dumps(entry) + '\n')
if any(x.startswith('--scrub=') for x in args):
sys.exit(0)
if '--buildsrpm' in args:
dest = pathlib.Path(option('--resultdir')); dest.mkdir(parents=True, exist_ok=True)
shutil.copyfile(os.environ['SCP_FIXTURE_SOURCE'], dest / 'python3-scp-0.14.5-1.src.rpm')
sys.exit(0)
if os.environ.get('SCP_MUTATE_SOURCE'):
with open(os.environ['SCP_MUTATE_SOURCE'], 'ab') as stream:
stream.write(b'changed after staging')
if os.environ.get('SCP_BUILD_STATUS', '43') != '0':
sys.exit(43)
if os.environ.get('SCP_EMPTY_OUTPUT') != '1':
dest = pathlib.Path(option('--resultdir')); dest.mkdir(parents=True, exist_ok=True)
for key in ('SCP_FIXTURE_BINARY', 'SCP_FIXTURE_SOURCE'):
source = pathlib.Path(os.environ[key]); shutil.copyfile(source, dest / source.name)
PYTHON
or die(read_binary("$tmp/fixture.log"));
copy("$RealBin/fixtures/srpm-mock.pl", "$tmp/bin/mock") or die $!;
chmod 0755, "$tmp/bin/mock";
sub scenario {
@@ -11,7 +11,7 @@ use JSON::PP qw(encode_json);
use Test::More;
use Text::ParseWords qw(shellwords);
use lib "$RealBin/../lib", "$RealBin/lib";
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);
+1 -58
View File
@@ -59,7 +59,7 @@ is_deeply([install_deps_command('rocky')], ['dnf', '-y', 'install', install_deps
exec($^X, "$RealBin/../mockbuild-all.pl", '--verify-repo', $repo, '--repo-root', $tmp) or die $!;
}
waitpid($pid, 0);
isnt($? >> 8, 0, "$version/$arch empty repository fails the full publication gate");
isnt((($? & 127) ? 128 + ($? & 127) : $? >> 8), 0, "$version/$arch empty repository fails the full publication gate");
open(my $output, '<', "$tmp/output") or die $!;
my $text = do {local $/; <$output>};
close($output);
@@ -67,61 +67,4 @@ is_deeply([install_deps_command('rocky')], ['dnf', '-y', 'install', install_deps
}
}
SKIP: {
skip 'native mock Python library and templates required', 66
if system('python3 -c "import mockbuild.config" >/dev/null 2>&1') != 0
|| !-f '/etc/mock/templates/openeuler-24.03.tpl';
my $tmp = tempdir(CLEANUP => 1);
my $loader = "$tmp/load.py";
open(my $fh, '>', $loader) or die $!;
print {$fh} <<'PYTHON';
import configparser
import json
from pathlib import Path
import shutil
import sys
import tempfile
from mockbuild.config import load_config
source = Path(sys.argv[1]).resolve()
with tempfile.TemporaryDirectory() as directory:
config_path = Path(directory)
(config_path / 'templates').mkdir()
for parent in ('openeuler-20.03-sp4.tpl', 'openeuler-22.03-sp4.tpl', 'openeuler-24.03.tpl'):
shutil.copyfile(Path('/etc/mock/templates') / parent, config_path / 'templates' / parent)
shutil.copyfile(source / 'templates/openeuler-lts-xcat.tpl', config_path / 'templates/openeuler-lts-xcat.tpl')
result = {}
for wrapper in sorted(source.glob('openeuler-*.cfg')):
config = load_config(str(config_path), str(wrapper))
repos = configparser.ConfigParser(interpolation=None)
repos.read_string(config['dnf.conf'])
result[wrapper.stem] = {key: config[key] for key in ('root', 'target_arch', 'legal_host_arches', 'releasever', 'dist', 'use_bootstrap_image')}
result[wrapper.stem]['repos'] = {section: dict(repos[section]) for section in repos.sections()}
print(json.dumps(result))
PYTHON
close($fh) or die $!;
open(my $pipe, '-|', 'python3', $loader, "$RealBin/../mock-configs") or die $!;
my $json = do {local $/; <$pipe>};
close($pipe) or die "native mock config loader failed: $?";
my $configs = decode_json($json);
for my $cell (@cells) {
my ($version, $release, $releasever, $arch) = @$cell;
my $target = "openeuler-$version-$arch";
my $config = $configs->{$target};
is($config->{root}, $target, "$target selects its own buildroot");
is($config->{target_arch}, $arch, "$target selects its native architecture");
is_deeply($config->{legal_host_arches}, [$arch], "$target requires a native host");
is($config->{releasever}, $releasever, "$target retains the release package convention");
is($config->{dist}, '', "$target retains the native empty dist macro");
ok(!$config->{use_bootstrap_image}, "$target constructs its bootstrap from signed native RPMs");
my $repos = $config->{repos};
my @names = $arch eq 'ppc64le' ? ('OS') : ('OS', 'everything', 'update');
is_deeply([sort grep {$_ ne 'main'} keys %$repos], [sort @names], "$target selects only published native repositories");
is($repos->{main}{gpgcheck}, '1', "$target requires native package signatures");
my $base = "https://repo.openeuler.org/openEuler-$release";
is_deeply([map {$repos->{$_}{baseurl}} @names], [map {"$base/$_/$arch/"} @names], "$target pins repository URLs to its exact release");
is_deeply([map {$repos->{$_}{gpgkey}} @names], [map {"$base/OS/$arch/RPM-GPG-KEY-openEuler"} @names], "$target uses the release signing key");
ok(!grep({$repos->{$_}{gpgcheck} ne '1' || $repos->{$_}{skip_if_unavailable} ne '0'} @names), "$target fails on unsigned packages or unavailable repositories");
}
}
done_testing();