summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rwxr-xr-xtest/integration-test-wrapper.py196
-rw-r--r--test/test-execute/exec-ambientcapabilities-dynuser.service1
-rw-r--r--test/test-execute/exec-dynamicuser-fixeduser-adm.service1
-rw-r--r--test/test-execute/exec-dynamicuser-fixeduser-games.service1
-rw-r--r--test/test-execute/exec-dynamicuser-fixeduser-one-supplementarygroup.service1
-rw-r--r--test/test-execute/exec-dynamicuser-fixeduser.service1
-rw-r--r--test/test-execute/exec-dynamicuser-runtimedirectory1.service1
-rw-r--r--test/test-execute/exec-dynamicuser-runtimedirectory2.service1
-rw-r--r--test/test-execute/exec-dynamicuser-runtimedirectory3.service1
-rw-r--r--test/test-execute/exec-dynamicuser-statedir-migrate-step2.service1
-rw-r--r--test/test-execute/exec-dynamicuser-statedir.service1
-rw-r--r--test/test-execute/exec-dynamicuser-supplementarygroups.service1
-rwxr-xr-xtest/test-network/systemd-networkd-tests.py2
-rwxr-xr-xtest/units/TEST-38-FREEZER.sh5
14 files changed, 188 insertions, 26 deletions
diff --git a/test/integration-test-wrapper.py b/test/integration-test-wrapper.py
index a3f90dc9fa..09dcda92e1 100755
--- a/test/integration-test-wrapper.py
+++ b/test/integration-test-wrapper.py
@@ -4,12 +4,15 @@
"""Test wrapper command for driving integration tests."""
import argparse
+import base64
+import dataclasses
import json
import os
import re
import shlex
import subprocess
import sys
+import tempfile
import textwrap
from pathlib import Path
@@ -33,6 +36,47 @@ ExecStart=false
"""
+def sandbox(args: argparse.Namespace) -> list[str]:
+ return [
+ args.mkosi,
+ '--directory', os.fspath(args.meson_source_dir),
+ '--extra-search-path', os.fspath(args.meson_build_dir),
+ 'sandbox',
+ ] # fmt: skip
+
+
+@dataclasses.dataclass(frozen=True)
+class Summary:
+ distribution: str
+ release: str
+ architecture: str
+ builddir: Path
+ environment: dict[str, str]
+
+ @classmethod
+ def get(cls, args: argparse.Namespace) -> 'Summary':
+ j = json.loads(
+ subprocess.run(
+ [
+ args.mkosi,
+ '--directory', os.fspath(args.meson_source_dir),
+ '--json',
+ 'summary',
+ ],
+ stdout=subprocess.PIPE,
+ text=True,
+ ).stdout
+ ) # fmt: skip
+
+ return Summary(
+ distribution=j['Images'][-1]['Distribution'],
+ release=j['Images'][-1]['Release'],
+ architecture=j['Images'][-1]['Architecture'],
+ builddir=Path(j['Images'][-1]['BuildDirectory']),
+ environment=j['Images'][-1]['Environment'],
+ )
+
+
def process_coredumps(args: argparse.Namespace, journal_file: Path) -> bool:
# Collect executable paths of all coredumps and filter out the expected ones.
@@ -42,11 +86,7 @@ def process_coredumps(args: argparse.Namespace, journal_file: Path) -> bool:
exclude_regex = None
result = subprocess.run(
- [
- args.mkosi,
- '--directory', os.fspath(args.meson_source_dir),
- '--extra-search-path', os.fspath(args.meson_build_dir),
- 'sandbox',
+ sandbox(args) + [
'coredumpctl',
'--file', journal_file,
'--json=short',
@@ -69,11 +109,7 @@ def process_coredumps(args: argparse.Namespace, journal_file: Path) -> bool:
return False
subprocess.run(
- [
- args.mkosi,
- '--directory', os.fspath(args.meson_source_dir),
- '--extra-search-path', os.fspath(args.meson_build_dir),
- 'sandbox',
+ sandbox(args) + [
'coredumpctl',
'--file', journal_file,
'--no-pager',
@@ -86,6 +122,119 @@ def process_coredumps(args: argparse.Namespace, journal_file: Path) -> bool:
return True
+def process_coverage(args: argparse.Namespace, summary: Summary, name: str, journal_file: Path) -> None:
+ coverage = subprocess.run(
+ sandbox(args) + [
+ 'journalctl',
+ '--file', journal_file,
+ '--field=COVERAGE_TAR',
+ ],
+ stdout=subprocess.PIPE,
+ text=True,
+ check=True,
+ ).stdout # fmt: skip
+
+ (args.meson_build_dir / 'test/coverage').mkdir(exist_ok=True)
+
+ initial = args.meson_build_dir / 'test/coverage/initial.coverage-info'
+ output = args.meson_build_dir / f'test/coverage/{name}.coverage-info'
+
+ for b64 in coverage.splitlines():
+ tarball = base64.b64decode(b64)
+
+ with tempfile.TemporaryDirectory(prefix='coverage-') as tmp:
+ subprocess.run(
+ sandbox(args) + [
+ 'tar',
+ '--extract',
+ '--file', '-',
+ '--directory', tmp,
+ '--keep-directory-symlink',
+ '--no-overwrite-dir',
+ '--zstd',
+ ],
+ input=tarball,
+ check=True,
+ ) # fmt: skip
+
+ for p in Path(tmp).iterdir():
+ if not p.name.startswith('#'):
+ continue
+
+ dst = Path(tmp) / p.name.replace('#', '/').lstrip('/')
+ dst.parent.mkdir(parents=True, exist_ok=True)
+ p.rename(dst)
+
+ subprocess.run(
+ sandbox(args) + [
+ 'find',
+ tmp,
+ '-name', '*.gcda',
+ '-size', '0',
+ '-delete',
+ ],
+ input=tarball,
+ check=True,
+ ) # fmt: skip
+
+ subprocess.run(
+ sandbox(args)
+ + [
+ 'rsync',
+ '--archive',
+ '--prune-empty-dirs',
+ '--include=*/',
+ '--include=*.gcno',
+ '--exclude=*',
+ f'{os.fspath(args.meson_build_dir / summary.builddir)}/',
+ os.fspath(Path(tmp) / 'work/build'),
+ ],
+ check=True,
+ )
+
+ subprocess.run(
+ sandbox(args)
+ + [
+ 'lcov',
+ *(
+ [
+ '--gcov-tool', 'llvm-cov',
+ '--gcov-tool', 'gcov',
+ ]
+ if summary.environment.get('LLVM', '0') == '1'
+ else []
+ ),
+ '--directory', tmp,
+ '--base-directory', 'src/',
+ '--capture',
+ '--exclude', '*.gperf',
+ '--output-file', f'{output}.new',
+ '--ignore-errors', 'inconsistent,inconsistent,source,negative',
+ '--substitute', 's#src/src#src#g',
+ '--no-external',
+ '--quiet',
+ ],
+ check=True,
+ ) # fmt: skip
+
+ subprocess.run(
+ sandbox(args)
+ + [
+ 'lcov',
+ '--ignore-errors', 'inconsistent,inconsistent,format,corrupt,empty',
+ '--add-tracefile', output if output.exists() else initial,
+ '--add-tracefile', f'{output}.new',
+ '--output-file', output,
+ '--quiet',
+ ],
+ check=True,
+ ) # fmt: skip
+
+ Path(f'{output}.new').unlink()
+
+ print(f'Wrote coverage report for {name} to {output}', file=sys.stderr)
+
+
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--mkosi', required=True)
@@ -127,6 +276,7 @@ def main() -> None:
keep_journal = os.getenv('TEST_SAVE_JOURNAL', 'fail')
shell = bool(int(os.getenv('TEST_SHELL', '0')))
+ summary = Summary.get(args)
if shell and not sys.stderr.isatty():
print(
@@ -250,6 +400,13 @@ def main() -> None:
coredumps = process_coredumps(args, journal_file)
+ if (
+ summary.environment.get('COVERAGE', '0') == '1'
+ and result.returncode in (args.exit_code, 77)
+ and not coredumps
+ ):
+ process_coverage(args, summary, name, journal_file)
+
if keep_journal == '0' or (
keep_journal == 'fail' and result.returncode in (args.exit_code, 77) and not coredumps
):
@@ -262,22 +419,11 @@ def main() -> None:
if os.getenv('GITHUB_ACTIONS'):
id = os.environ['GITHUB_RUN_ID']
+ workflow = os.environ['GITHUB_WORKFLOW']
iteration = os.environ['GITHUB_RUN_ATTEMPT']
- j = json.loads(
- subprocess.run(
- [
- args.mkosi,
- '--directory', os.fspath(args.meson_source_dir),
- '--json',
- 'summary',
- ],
- stdout=subprocess.PIPE,
- text=True,
- ).stdout
- ) # fmt: skip
- distribution = j['Images'][-1]['Distribution']
- release = j['Images'][-1]['Release']
- artifact = f'ci-mkosi-{id}-{iteration}-{distribution}-{release}-failed-test-journals'
+ artifact = (
+ f'ci-{workflow}-{id}-{iteration}-{summary.distribution}-{summary.release}-failed-test-journals'
+ )
ops += [f'gh run download {id} --name {artifact} -D ci/{artifact}']
journal_file = Path(f'ci/{artifact}/test/journal/{name}.journal')
diff --git a/test/test-execute/exec-ambientcapabilities-dynuser.service b/test/test-execute/exec-ambientcapabilities-dynuser.service
index ab815f39a3..b927c7dbca 100644
--- a/test/test-execute/exec-ambientcapabilities-dynuser.service
+++ b/test/test-execute/exec-ambientcapabilities-dynuser.service
@@ -9,3 +9,4 @@ AmbientCapabilities=CAP_CHOWN CAP_SETUID CAP_NET_RAW
DynamicUser=yes
PrivateUsers=yes
EnvironmentFile=-/usr/lib/systemd/systemd-asan-env
+ReadWritePaths=-/coverage
diff --git a/test/test-execute/exec-dynamicuser-fixeduser-adm.service b/test/test-execute/exec-dynamicuser-fixeduser-adm.service
index 1b7f232cd1..3a7f8aef60 100644
--- a/test/test-execute/exec-dynamicuser-fixeduser-adm.service
+++ b/test/test-execute/exec-dynamicuser-fixeduser-adm.service
@@ -10,3 +10,4 @@ ExecStart=sh -x -c 'test "$$(id -nG)" = "adm" && test "$$(id -ng)" = "adm" && te
ExecStart=sh -x -c 'test "$$(id -nG)" = "adm" && test "$$(id -ng)" = "adm" && test "$$(id -nu)" = "adm"'
DynamicUser=yes
User=adm
+ReadWritePaths=-/coverage
diff --git a/test/test-execute/exec-dynamicuser-fixeduser-games.service b/test/test-execute/exec-dynamicuser-fixeduser-games.service
index b13c23a74d..40048d27a8 100644
--- a/test/test-execute/exec-dynamicuser-fixeduser-games.service
+++ b/test/test-execute/exec-dynamicuser-fixeduser-games.service
@@ -10,3 +10,4 @@ ExecStart=sh -x -c 'test "$$(id -nG)" = "games" && test "$$(id -ng)" = "games" &
ExecStart=sh -x -c 'test "$$(id -nG)" = "games" && test "$$(id -ng)" = "games" && test "$$(id -nu)" = "games"'
DynamicUser=yes
User=games
+ReadWritePaths=-/coverage
diff --git a/test/test-execute/exec-dynamicuser-fixeduser-one-supplementarygroup.service b/test/test-execute/exec-dynamicuser-fixeduser-one-supplementarygroup.service
index e494c33551..e58b524033 100644
--- a/test/test-execute/exec-dynamicuser-fixeduser-one-supplementarygroup.service
+++ b/test/test-execute/exec-dynamicuser-fixeduser-one-supplementarygroup.service
@@ -9,3 +9,4 @@ Type=oneshot
User=1
DynamicUser=yes
SupplementaryGroups=1
+ReadWritePaths=-/coverage
diff --git a/test/test-execute/exec-dynamicuser-fixeduser.service b/test/test-execute/exec-dynamicuser-fixeduser.service
index 4ebfc20cde..8e5244d891 100644
--- a/test/test-execute/exec-dynamicuser-fixeduser.service
+++ b/test/test-execute/exec-dynamicuser-fixeduser.service
@@ -8,3 +8,4 @@ ExecStart=sh -x -c 'test "$$(id -g)" = "1" && test "$$(id -u)" = "1"'
Type=oneshot
User=1
DynamicUser=yes
+ReadWritePaths=-/coverage
diff --git a/test/test-execute/exec-dynamicuser-runtimedirectory1.service b/test/test-execute/exec-dynamicuser-runtimedirectory1.service
index 59d3bf0884..671b316736 100644
--- a/test/test-execute/exec-dynamicuser-runtimedirectory1.service
+++ b/test/test-execute/exec-dynamicuser-runtimedirectory1.service
@@ -11,3 +11,4 @@ RuntimeDirectory=test-exec_runtimedirectorypreserve
RuntimeDirectoryPreserve=yes
DynamicUser=yes
EnvironmentFile=-/usr/lib/systemd/systemd-asan-env
+ReadWritePaths=-/coverage
diff --git a/test/test-execute/exec-dynamicuser-runtimedirectory2.service b/test/test-execute/exec-dynamicuser-runtimedirectory2.service
index 6ff9d7503a..cdb80848e3 100644
--- a/test/test-execute/exec-dynamicuser-runtimedirectory2.service
+++ b/test/test-execute/exec-dynamicuser-runtimedirectory2.service
@@ -12,3 +12,4 @@ RuntimeDirectory=test-exec_runtimedirectorypreserve
RuntimeDirectoryPreserve=yes
DynamicUser=yes
EnvironmentFile=-/usr/lib/systemd/systemd-asan-env
+ReadWritePaths=-/coverage
diff --git a/test/test-execute/exec-dynamicuser-runtimedirectory3.service b/test/test-execute/exec-dynamicuser-runtimedirectory3.service
index cebb819476..51a9e44c6f 100644
--- a/test/test-execute/exec-dynamicuser-runtimedirectory3.service
+++ b/test/test-execute/exec-dynamicuser-runtimedirectory3.service
@@ -11,3 +11,4 @@ Type=oneshot
RuntimeDirectory=test-exec_runtimedirectorypreserve
DynamicUser=yes
EnvironmentFile=-/usr/lib/systemd/systemd-asan-env
+ReadWritePaths=-/coverage
diff --git a/test/test-execute/exec-dynamicuser-statedir-migrate-step2.service b/test/test-execute/exec-dynamicuser-statedir-migrate-step2.service
index 7261f4a174..f22862378c 100644
--- a/test/test-execute/exec-dynamicuser-statedir-migrate-step2.service
+++ b/test/test-execute/exec-dynamicuser-statedir-migrate-step2.service
@@ -25,3 +25,4 @@ Type=oneshot
DynamicUser=yes
StateDirectory=test-dynamicuser-migrate test-dynamicuser-migrate2/hoge
EnvironmentFile=-/usr/lib/systemd/systemd-asan-env
+ReadWritePaths=-/coverage
diff --git a/test/test-execute/exec-dynamicuser-statedir.service b/test/test-execute/exec-dynamicuser-statedir.service
index 636a70259c..1e4fe818ac 100644
--- a/test/test-execute/exec-dynamicuser-statedir.service
+++ b/test/test-execute/exec-dynamicuser-statedir.service
@@ -84,3 +84,4 @@ Type=oneshot
DynamicUser=yes
StateDirectory=waldo quux/pief aaa/bbb aaa aaa/ccc xxx/yyy:aaa/111 xxx:aaa/222 xxx/zzz:aaa/333 abc:d\:ef
EnvironmentFile=-/usr/lib/systemd/systemd-asan-env
+ReadWritePaths=-/coverage
diff --git a/test/test-execute/exec-dynamicuser-supplementarygroups.service b/test/test-execute/exec-dynamicuser-supplementarygroups.service
index be1b8f76f2..fd88a790e4 100644
--- a/test/test-execute/exec-dynamicuser-supplementarygroups.service
+++ b/test/test-execute/exec-dynamicuser-supplementarygroups.service
@@ -9,3 +9,4 @@ Type=oneshot
DynamicUser=yes
SupplementaryGroups=1 2
EnvironmentFile=-/usr/lib/systemd/systemd-asan-env
+ReadWritePaths=-/coverage
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index 215f3cb1cc..1fd1b2290f 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -8655,7 +8655,7 @@ if __name__ == '__main__':
asan_options = ns.asan_options
lsan_options = ns.lsan_options
ubsan_options = ns.ubsan_options
- with_coverage = ns.with_coverage
+ with_coverage = ns.with_coverage or "COVERAGE_BUILD_DIR" in os.environ
show_journal = ns.show_journal
if use_valgrind:
diff --git a/test/units/TEST-38-FREEZER.sh b/test/units/TEST-38-FREEZER.sh
index 07597843e2..4c483df46a 100755
--- a/test/units/TEST-38-FREEZER.sh
+++ b/test/units/TEST-38-FREEZER.sh
@@ -7,6 +7,11 @@ set -o pipefail
# shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/test-control.sh
+if [[ -n "${COVERAGE_BUILD_DIR:-}" ]]; then
+ echo "TEST-38-FREEZER freezes when systemd is built with coverage enabled" >/skipped
+ exit 77
+fi
+
systemd-analyze log-level debug
unit=TEST-38-FREEZER-sleep.service