diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000000..73409e53ef --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,145 @@ +--- +# SPDX-License-Identifier: LGPL-2.1-or-later +name: coverage + +on: + schedule: + # Calculate coverage daily at midnight + - cron: '0 0 * * *' + +permissions: + contents: read + +jobs: + coverage: + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: systemd/mkosi@07ef37c4c0dad5dfc6cec86c967a7600df1cd88c + + # Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space + # immediately, we remove the files in the background. However, we first move them to a different location + # so that nothing tries to use anything in these directories anymore while we're busy deleting them. + - name: Free disk space + run: | + sudo mv /usr/local /usr/local.trash + sudo mv /opt/hostedtoolcache /opt/hostedtoolcache.trash + sudo systemd-run rm -rf /usr/local.trash /opt/hostedtoolcache.trash + + - name: Btrfs + run: | + truncate --size=100G btrfs.raw + mkfs.btrfs btrfs.raw + sudo mkdir /mnt/mkosi + LOOP="$(sudo losetup --find --show --direct-io=on btrfs.raw)" + sudo mount "$LOOP" /mnt/mkosi --options compress=zstd:1,user_subvol_rm_allowed,noatime,discard=async,space_cache=v2 + sudo chown "$(id -u):$(id -g)" /mnt/mkosi + mkdir /mnt/mkosi/tmp + echo "TMPDIR=/mnt/mkosi/tmp" >>"$GITHUB_ENV" + ln -s /mnt/mkosi/build build + + - name: Configure + run: | + # XXX: drop after the HyperV bug that breaks secure boot KVM guests is solved + sed -i "s/'firmware'\s*:\s*'auto'/'firmware' : 'uefi'/g" test/*/meson.build + + tee mkosi.local.conf <"$BUILDROOT/usr/lib/systemd/system/service.d/99-gcov-override.conf" <"$BUILDROOT/usr/lib/systemd/system/$service.service.d/99-gcov-rwpaths-override.conf" <"$BUILDROOT/usr/lib/systemd/user/test-.service.d/99-gcov-rwpaths-override.conf" <= 0); + ASSERT_OK(mkdtemp_malloc(NULL, &tmp)); - assert_se(setenv("CREDENTIALS_DIRECTORY", tmp, /* override= */ true) >= 0); + ASSERT_OK_ERRNO(setenv("CREDENTIALS_DIRECTORY", tmp, /* override= */ true)); - assert_se(read_credential_strings_many("foo", &x, "bar", &y) == 0); + ASSERT_OK_ZERO(read_credential_strings_many("foo", &x, "bar", &y)); ASSERT_NULL(x); ASSERT_NULL(y); - assert_se(p = path_join(tmp, "bar")); - assert_se(write_string_file(p, "piff", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_AVOID_NEWLINE) >= 0); + ASSERT_NOT_NULL(p = path_join(tmp, "bar")); + ASSERT_OK(write_string_file(p, "piff", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_AVOID_NEWLINE)); - assert_se(read_credential_strings_many("foo", &x, "bar", &y) == 0); + ASSERT_OK_ZERO(read_credential_strings_many("foo", &x, "bar", &y)); ASSERT_NULL(x); ASSERT_STREQ(y, "piff"); - assert_se(write_string_file(p, "paff", WRITE_STRING_FILE_TRUNCATE|WRITE_STRING_FILE_AVOID_NEWLINE) >= 0); + ASSERT_OK(write_string_file(p, "paff", WRITE_STRING_FILE_TRUNCATE|WRITE_STRING_FILE_AVOID_NEWLINE)); - assert_se(read_credential_strings_many("foo", &x, "bar", &y) == 0); + ASSERT_OK_ZERO(read_credential_strings_many("foo", &x, "bar", &y)); ASSERT_NULL(x); ASSERT_STREQ(y, "paff"); p = mfree(p); - assert_se(p = path_join(tmp, "foo")); - assert_se(write_string_file(p, "knurz", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_AVOID_NEWLINE) >= 0); + ASSERT_NOT_NULL(p = path_join(tmp, "foo")); + ASSERT_OK(write_string_file(p, "knurz", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_AVOID_NEWLINE)); - assert_se(read_credential_strings_many("foo", &x, "bar", &y) >= 0); + ASSERT_OK(read_credential_strings_many("foo", &x, "bar", &y)); ASSERT_STREQ(x, "knurz"); ASSERT_STREQ(y, "paff"); p = mfree(p); - assert_se(p = path_join(tmp, "bazz")); - assert_se(f = fopen(p, "w")); - assert_se(fwrite("x\0y", 1, 3, f) == 3); /* embedded NUL byte should result in EBADMSG when reading back with read_credential_strings_many() */ + ASSERT_NOT_NULL(p = path_join(tmp, "bazz")); + ASSERT_NOT_NULL(f = fopen(p, "w")); + ASSERT_EQ(fwrite("x\0y", 1, 3, f), 3UL); /* embedded NUL byte should result in EBADMSG when reading back with read_credential_strings_many() */ f = safe_fclose(f); y = mfree(y); - assert_se(read_credential_strings_many("bazz", &x, "bar", &y) == -EBADMSG); + ASSERT_ERROR(read_credential_strings_many("bazz", &x, "bar", &y), EBADMSG); ASSERT_STREQ(x, "knurz"); ASSERT_STREQ(y, "paff"); if (saved) - assert_se(setenv("CREDENTIALS_DIRECTORY", saved, /* override= */ 1) >= 0); + ASSERT_OK_ERRNO(setenv("CREDENTIALS_DIRECTORY", saved, /* override= */ 1)); else - assert_se(unsetenv("CREDENTIALS_DIRECTORY") >= 0); + ASSERT_OK_ERRNO(unsetenv("CREDENTIALS_DIRECTORY")); } TEST(credential_name_valid) { char buf[NAME_MAX+2]; - assert_se(!credential_name_valid(NULL)); - assert_se(!credential_name_valid("")); - assert_se(!credential_name_valid(".")); - assert_se(!credential_name_valid("..")); - assert_se(!credential_name_valid("foo/bar")); - assert_se(credential_name_valid("foo")); + ASSERT_FALSE(credential_name_valid(NULL)); + ASSERT_FALSE(credential_name_valid("")); + ASSERT_FALSE(credential_name_valid(".")); + ASSERT_FALSE(credential_name_valid("..")); + ASSERT_FALSE(credential_name_valid("foo/bar")); + ASSERT_TRUE(credential_name_valid("foo")); memset(buf, 'x', sizeof(buf)-1); buf[sizeof(buf)-1] = 0; - assert_se(!credential_name_valid(buf)); + ASSERT_FALSE(credential_name_valid(buf)); buf[sizeof(buf)-2] = 0; - assert_se(credential_name_valid(buf)); + ASSERT_TRUE(credential_name_valid(buf)); } TEST(credential_glob_valid) { char buf[NAME_MAX+2]; - assert_se(!credential_glob_valid(NULL)); - assert_se(!credential_glob_valid("")); - assert_se(!credential_glob_valid(".")); - assert_se(!credential_glob_valid("..")); - assert_se(!credential_glob_valid("foo/bar")); - assert_se(credential_glob_valid("foo")); - assert_se(credential_glob_valid("foo*")); - assert_se(credential_glob_valid("x*")); - assert_se(credential_glob_valid("*")); - assert_se(!credential_glob_valid("?")); - assert_se(!credential_glob_valid("*a")); - assert_se(!credential_glob_valid("a?")); - assert_se(!credential_glob_valid("a[abc]")); - assert_se(!credential_glob_valid("a[abc]")); + ASSERT_FALSE(credential_glob_valid(NULL)); + ASSERT_FALSE(credential_glob_valid("")); + ASSERT_FALSE(credential_glob_valid(".")); + ASSERT_FALSE(credential_glob_valid("..")); + ASSERT_FALSE(credential_glob_valid("foo/bar")); + ASSERT_TRUE(credential_glob_valid("foo")); + ASSERT_TRUE(credential_glob_valid("foo*")); + ASSERT_TRUE(credential_glob_valid("x*")); + ASSERT_TRUE(credential_glob_valid("*")); + ASSERT_FALSE(credential_glob_valid("?")); + ASSERT_FALSE(credential_glob_valid("*a")); + ASSERT_FALSE(credential_glob_valid("a?")); + ASSERT_FALSE(credential_glob_valid("a[abc]")); + ASSERT_FALSE(credential_glob_valid("a[abc]")); memset(buf, 'x', sizeof(buf)-1); buf[sizeof(buf)-1] = 0; - assert_se(!credential_glob_valid(buf)); + ASSERT_FALSE(credential_glob_valid(buf)); buf[sizeof(buf)-2] = 0; - assert_se(credential_glob_valid(buf)); + ASSERT_TRUE(credential_glob_valid(buf)); buf[sizeof(buf)-2] = '*'; - assert_se(credential_glob_valid(buf)); + ASSERT_TRUE(credential_glob_valid(buf)); } static void test_encrypt_decrypt_with(sd_id128_t mode, uid_t uid) { @@ -152,7 +152,7 @@ static void test_encrypt_decrypt_with(sd_id128_t mode, uid_t uid) { return; } - assert_se(r >= 0); + ASSERT_OK(r); _cleanup_(iovec_done) struct iovec decrypted = {}; r = decrypt_credential_and_warn( @@ -164,7 +164,7 @@ static void test_encrypt_decrypt_with(sd_id128_t mode, uid_t uid) { &encrypted, CREDENTIAL_ALLOW_NULL, &decrypted); - assert_se(r == -EREMOTE); /* name didn't match */ + ASSERT_ERROR(r, EREMOTE); /* name didn't match */ r = decrypt_credential_and_warn( "foo", @@ -175,9 +175,9 @@ static void test_encrypt_decrypt_with(sd_id128_t mode, uid_t uid) { &encrypted, CREDENTIAL_ALLOW_NULL, &decrypted); - assert_se(r >= 0); + ASSERT_OK(r); - assert_se(iovec_memcmp(&plaintext, &decrypted) == 0); + ASSERT_EQ(iovec_memcmp(&plaintext, &decrypted), 0); } static bool try_tpm2(void) { @@ -203,17 +203,17 @@ TEST(credential_encrypt_decrypt) { test_encrypt_decrypt_with(CRED_AES256_GCM_BY_NULL, UID_INVALID); - assert_se(mkdtemp_malloc(NULL, &d) >= 0); + ASSERT_OK(mkdtemp_malloc(NULL, &d)); j = path_join(d, "secret"); - assert_se(j); + ASSERT_NOT_NULL(j); const char *e = getenv("SYSTEMD_CREDENTIAL_SECRET"); _cleanup_free_ char *ec = NULL; if (e) - assert_se(ec = strdup(e)); + ASSERT_NOT_NULL(ec = strdup(e)); - assert_se(setenv("SYSTEMD_CREDENTIAL_SECRET", j, true) >= 0); + ASSERT_OK_ERRNO(setenv("SYSTEMD_CREDENTIAL_SECRET", j, true)); test_encrypt_decrypt_with(CRED_AES256_GCM_BY_HOST, UID_INVALID); test_encrypt_decrypt_with(CRED_AES256_GCM_BY_HOST_SCOPED, 0); @@ -225,7 +225,7 @@ TEST(credential_encrypt_decrypt) { } if (ec) - assert_se(setenv("SYSTEMD_CREDENTIAL_SECRET", ec, true) >= 0); + ASSERT_OK_ERRNO(setenv("SYSTEMD_CREDENTIAL_SECRET", ec, true)); } TEST(mime_type_matches) { @@ -246,10 +246,10 @@ TEST(mime_type_matches) { FOREACH_ELEMENT(t, tags) { _cleanup_free_ char *encoded = NULL; - assert_se(base64mem(t, sizeof(sd_id128_t), &encoded) >= 0); + ASSERT_OK(base64mem(t, sizeof(sd_id128_t), &encoded)); /* Validate that the size matches expectations for the 4/3 factor size increase (rounding up) */ - assert_se(strlen(encoded) == DIV_ROUND_UP((128U / 8U), 3U) * 4U); + ASSERT_EQ(strlen(encoded), DIV_ROUND_UP((128U / 8U), 3U) * 4U); /* Cut off rounded string where the ID ends, but now round down to get rid of characters that might contain follow-up data */ encoded[128 / 6] = 0; diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 95ccf5490d..de575ec1e6 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -1448,8 +1448,10 @@ static int prepare_ns(const char *process_name) { _cleanup_free_ char *unit_dir = NULL, *build_dir = NULL, *build_dir_mount = NULL; int ret; - /* Make "/" read-only. */ - ASSERT_OK(mount_nofollow_verbose(LOG_DEBUG, NULL, "/", NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL)); + const char *coverage = getenv("COVERAGE_BUILD_DIR"); + if (!coverage) + /* Make "/" read-only. */ + ASSERT_OK(mount_nofollow_verbose(LOG_DEBUG, NULL, "/", NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL)); /* Creating a new user namespace in the above means all MS_SHARED mounts become MS_SLAVE. * Let's put them back to MS_SHARED here, since that's what we want as defaults. (This will 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