summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2023-05-05 14:46:34 +0200
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2023-05-09 08:11:10 +0200
commit0454cf05d38d289474ca65c1917d414b2958f6b5 (patch)
treeb6ea233b071cd7da497d643fc69a0ef2acd6fb6f /test
parent09ea351b6fce2ac3be19fc8af40828b722cd6dc4 (diff)
downloadsystemd-0454cf05d38d289474ca65c1917d414b2958f6b5.tar.gz
test: rework how udev-test is invoked
As part of the build, we would populate build/test/sys/ using sys-script.py, and then udev-test.p[ly] would create a tmpfs instance on build/test/tmpfs and copy the sys tree to build/test/tmpfs/sys. Also, we had udev-test.p[ly] which called test-udev. test-udev was marked as a manual test and installed, but neither udev-test.p[ly] or sys-script.py were. test-udev is renamed to udev-rule-runner, which reduces confusion and frees up the test-udev name. udev-test.py is renamed to test-udev.py. All three files are now installed. test-udev.py is modified to internally call sys-script.py to set up the sys tree. Copying and creating it from scratch should take the same amount of time. We avoid having a magic directory, everything is now done underneath a temporary directory. test-udev.py is now a normal installed test, and run-unit-tests.py will pick it up. When test-udev.py is invoked from meson, the path to udev-rule-runner is passed via envvar; when it is invoked via run-unit-tests.py or directly, it looks for udev-rule-runner in a relative path. The goal of this whole change is to let Debian drop the 'udev' test. It called sys-script.py and udev-test.pl from the source directory and had to recreate a bunch of the logic. Now test-udev.py will now be called via 'upstream'.
Diffstat (limited to 'test')
-rw-r--r--test/meson.build19
-rwxr-xr-xtest/test-udev.py (renamed from test/udev-test.py)64
2 files changed, 52 insertions, 31 deletions
diff --git a/test/meson.build b/test/meson.build
index 8d6667b405..f53971416e 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -123,19 +123,14 @@ endif
############################################################
-# prepare test/sys tree
-sys_script_py = find_program('sys-script.py')
-custom_target(
- 'sys',
- command : [sys_script_py, meson.current_build_dir()],
- output : 'sys',
- build_by_default : want_tests != 'false')
+sys_script_py = files('sys-script.py')
+test_udev_py = files('test-udev.py')
-if want_tests != 'false'
- test('udev-test',
- files('udev-test.py'),
- args : ['-v'],
- timeout : 180)
+if install_tests
+ install_data(
+ sys_script_py,
+ test_udev_py,
+ install_dir : unittestsdir)
endif
############################################################
diff --git a/test/udev-test.py b/test/test-udev.py
index 5ddda3865f..86937205de 100755
--- a/test/udev-test.py
+++ b/test/test-udev.py
@@ -4,6 +4,7 @@
# pylint: disable=missing-docstring,redefined-outer-name,invalid-name
# pylint: disable=unspecified-encoding,no-else-return,line-too-long,too-many-lines
# pylint: disable=multiple-imports,too-many-instance-attributes,consider-using-with
+# pylint: disable=global-statement
# udev test
#
@@ -26,9 +27,10 @@ import re
import stat
import subprocess
import sys
+import tempfile
import textwrap
from pathlib import Path
-from typing import Optional
+from typing import Callable, Optional
try:
import pytest
@@ -37,16 +39,15 @@ except ImportError as e:
sys.exit(77)
-# TODO: pass path to test-udev from outside
-UDEV_BIN = './test-udev'
-UDEV_RUN = Path('test/run')
-UDEV_RULES_DIR = UDEV_RUN / 'udev/rules.d'
-UDEV_RULES = UDEV_RULES_DIR / 'udev-test.rules'
+SYS_SCRIPT = Path(__file__).with_name('sys-script.py')
+try:
+ UDEV_BIN = Path(os.environ['UDEV_RULE_RUNNER'])
+except KeyError:
+ UDEV_BIN = Path(__file__).parent / 'manual/udev-rule-runner'
+UDEV_BIN = UDEV_BIN.absolute()
-UDEV_RUN = Path('test/run')
-UDEV_TMPFS = Path('test/tmpfs')
-UDEV_DEV = UDEV_TMPFS / 'dev'
-UDEV_SYS = UDEV_TMPFS / 'sys'
+# Those will be set by the udev_setup() fixture
+UDEV_RUN = UDEV_RULES = UDEV_DEV = UDEV_SYS = None
# Relax sd-device's sysfs verification, since we want to provide a fake sysfs
# here that actually is a tmpfs.
@@ -178,14 +179,23 @@ class Rules:
desc: str
devices: list[Device]
rules: str
+ device_generator: Callable = None
repeat: int = 1
delay: Optional[int] = None
@classmethod
- def new(cls, desc: str, *devices, rules = None, **kwargs):
+ def new(cls, desc: str, *devices, rules=None, device_generator=None, **kwargs):
assert rules.startswith('\n')
rules = textwrap.dedent(rules[1:]) if rules else ''
- return cls(desc, devices, rules, **kwargs)
+
+ assert bool(devices) ^ bool(device_generator)
+
+ return cls(desc, devices, rules, device_generator=device_generator, **kwargs)
+
+ def generate_devices(self) -> None:
+ # We can't do this when the class is created, because setup is done later.
+ if self.device_generator:
+ self.devices = self.device_generator()
def create_rules_file(self) -> None:
# create temporary rules
@@ -2298,7 +2308,8 @@ SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c \"printf %%s 'foo1 foo2' | grep 'foo1 f
Rules.new(
'all_block_devs',
- *all_block_devs(lambda name: (["blockdev"], None) if name.endswith('/sda6') else (None, None)),
+ device_generator = lambda: \
+ all_block_devs(lambda name: (["blockdev"], None) if name.endswith('/sda6') else (None, None)),
repeat = 10,
rules = r"""
SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sd*", SYMLINK+="blockdev"
@@ -2344,15 +2355,27 @@ def udev_setup():
if issue:
pytest.skip(issue)
- subprocess.run(['umount', UDEV_TMPFS],
+ global UDEV_RUN, UDEV_RULES, UDEV_DEV, UDEV_SYS
+
+ _tmpdir = tempfile.TemporaryDirectory()
+ tmpdir = Path(_tmpdir.name)
+
+ UDEV_RUN = tmpdir / 'run'
+ UDEV_RULES = UDEV_RUN / 'udev-test.rules'
+
+ udev_tmpfs = tmpdir / 'tmpfs'
+ UDEV_DEV = udev_tmpfs / 'dev'
+ UDEV_SYS = udev_tmpfs / 'sys'
+
+ subprocess.run(['umount', udev_tmpfs],
stderr=subprocess.DEVNULL,
check=False)
- UDEV_TMPFS.mkdir(exist_ok=True, parents=True)
+ udev_tmpfs.mkdir(exist_ok=True, parents=True)
subprocess.check_call(['mount', '-v',
'-t', 'tmpfs',
'-o', 'rw,mode=0755,nosuid,noexec',
- 'tmpfs', UDEV_TMPFS])
+ 'tmpfs', udev_tmpfs])
UDEV_DEV.mkdir(exist_ok=True)
# setting group and mode of udev_dev ensures the tests work
@@ -2367,10 +2390,12 @@ def udev_setup():
os.mknod(sda, 0o600 | stat.S_IFBLK, os.makedev(8, 0))
sda.unlink()
- subprocess.check_call(['cp', '-r', 'test/sys/', UDEV_SYS])
+ subprocess.check_call([SYS_SCRIPT, UDEV_SYS.parent])
subprocess.check_call(['rm', '-rf', UDEV_RUN])
UDEV_RUN.mkdir(parents=True)
+ os.chdir(tmpdir)
+
if subprocess.run([UDEV_BIN, 'check'],
check=False).returncode != 0:
pytest.skip(f'{UDEV_BIN} failed to set up the environment, skipping the test',
@@ -2379,8 +2404,8 @@ def udev_setup():
yield
subprocess.check_call(['rm', '-rf', UDEV_RUN])
- subprocess.check_call(['umount', '-v', UDEV_TMPFS])
- UDEV_TMPFS.rmdir()
+ subprocess.check_call(['umount', '-v', udev_tmpfs])
+ udev_tmpfs.rmdir()
@pytest.mark.parametrize("rules", RULES, ids=(rule.desc for rule in RULES))
@@ -2388,6 +2413,7 @@ def test_udev(rules: Rules, udev_setup):
assert udev_setup is None
rules.create_rules_file()
+ rules.generate_devices()
for _ in range(rules.repeat):
fork_and_run_udev('add', rules)