]>
git.ipfire.org Git - thirdparty/systemd.git/blob - test/integration-test-wrapper.py
2 # SPDX-License-Identifier: LGPL-2.1-or-later
4 '''Test wrapper command for driving integration tests.
6 Note: This is deliberately rough and only intended to drive existing tests
7 with the expectation that as part of formally defining the API it will be tidy.
18 from pathlib
import Path
21 EMERGENCY_EXIT_DROPIN
= """\
23 Wants=emergency-exit.service
27 EMERGENCY_EXIT_SERVICE
= """\
29 DefaultDependencies=no
30 Conflicts=shutdown.target
31 Conflicts=rescue.service
32 Before=shutdown.target
42 parser
= argparse
.ArgumentParser(description
=__doc__
)
43 parser
.add_argument('--meson-source-dir', required
=True, type=Path
)
44 parser
.add_argument('--meson-build-dir', required
=True, type=Path
)
45 parser
.add_argument('--name', required
=True)
46 parser
.add_argument('--unit', required
=True)
47 parser
.add_argument('--storage', required
=True)
48 parser
.add_argument('--firmware', required
=True)
49 parser
.add_argument('--slow', action
=argparse
.BooleanOptionalAction
)
50 parser
.add_argument('mkosi_args', nargs
="*")
51 args
= parser
.parse_args()
53 if not bool(int(os
.getenv("SYSTEMD_INTEGRATION_TESTS", "0"))):
54 print(f
"SYSTEMD_INTEGRATION_TESTS=1 not found in environment, skipping {args.name}", file=sys
.stderr
)
57 if args
.slow
and not bool(int(os
.getenv("SYSTEMD_SLOW_TESTS", "0"))):
58 print(f
"SYSTEMD_SLOW_TESTS=1 not found in environment, skipping {args.name}", file=sys
.stderr
)
61 name
= args
.name
+ (f
"-{i}" if (i
:= os
.getenv("MESON_TEST_ITERATION")) else "")
63 dropin
= textwrap
.dedent(
67 SuccessActionExitStatus=123
70 StandardOutput=journal+console
74 if os
.getenv("TEST_MATCH_SUBTEST"):
75 dropin
+= textwrap
.dedent(
78 Environment=TEST_MATCH_SUBTEST={os.environ["TEST_MATCH_SUBTEST"]}
82 if os
.getenv("TEST_MATCH_TESTCASE"):
83 dropin
+= textwrap
.dedent(
86 Environment=TEST_MATCH_TESTCASE={os.environ["TEST_MATCH_TESTCASE"]}
90 if not sys
.stderr
.isatty():
91 dropin
+= textwrap
.dedent(
98 journal_file
= (args
.meson_build_dir
/ (f
"test/journal/{name}.journal")).absolute()
99 journal_file
.unlink(missing_ok
=True)
105 '--directory', os
.fspath(args
.meson_source_dir
),
106 '--output-dir', os
.fspath(args
.meson_build_dir
/ 'mkosi.output'),
107 '--extra-search-path', os
.fspath(args
.meson_build_dir
),
110 *(['--forward-journal', journal_file
] if journal_file
else []),
114 f
"systemd.extra-unit.emergency-exit.service={shlex.quote(EMERGENCY_EXIT_SERVICE)}",
116 f
"systemd.unit-dropin.emergency.target={shlex.quote(EMERGENCY_EXIT_DROPIN)}",
118 if not sys
.stderr
.isatty()
122 f
"systemd.unit-dropin.{args.unit}={shlex.quote(dropin)}",
123 '--runtime-network=none',
124 '--runtime-scratch=no',
127 '--qemu-firmware', args
.firmware
,
128 '--kernel-command-line-extra',
130 'systemd.hostname=H',
131 f
"SYSTEMD_UNIT_PATH=/usr/lib/systemd/tests/testdata/{args.name}.units:/usr/lib/systemd/tests/testdata/units:",
132 f
"systemd.unit={args.unit}",
133 'systemd.mask=systemd-networkd-wait-online.service',
136 "systemd.mask=serial-getty@.service",
137 "systemd.show_status=no",
138 "systemd.crash_shell=0",
139 "systemd.crash_action=poweroff",
141 if not sys
.stderr
.isatty()
145 '--credential', f
"journal.storage={'persistent' if sys.stderr.isatty() else args.storage}",
149 result
= subprocess
.run(cmd
)
151 # Return code 123 is the expected success code
152 if result
.returncode
in (123, 77):
153 # Do not keep journal files for tests that don't fail.
155 journal_file
.unlink(missing_ok
=True)
157 exit(0 if result
.returncode
== 123 else 77)
162 if os
.getenv("GITHUB_ACTIONS"):
163 id = os
.environ
["GITHUB_RUN_ID"]
164 iteration
= os
.environ
["GITHUB_RUN_ATTEMPT"]
169 "--directory", os
.fspath(args
.meson_source_dir
),
173 stdout
=subprocess
.PIPE
,
177 images
= {image
["Image"]: image
for image
in j
["Images"]}
178 distribution
= images
["system"]["Distribution"]
179 release
= images
["system"]["Release"]
180 artifact
= f
"ci-mkosi-{id}-{iteration}-{distribution}-{release}-failed-test-journals"
181 ops
+= [f
"gh run download {id} --name {artifact} -D ci/{artifact}"]
182 journal_file
= Path(f
"ci/{artifact}/test/journal/{name}.journal")
184 ops
+= [f
"journalctl --file {journal_file} --no-hostname -o short-monotonic -u {args.unit} -p info"]
186 print("Test failed, relevant logs can be viewed with: \n\n"
187 f
"{(' && '.join(ops))}\n", file=sys
.stderr
)
189 # 0 also means we failed so translate that to a non-zero exit code to mark the test as failed.
190 exit(result
.returncode
or 1)
193 if __name__
== '__main__':