linuxwacom / libwacom

libwacom is a tablet description library
Other
336 stars 173 forks source link

Pytests fails 2.4.0 if systemd-hwdb is missing #515

Closed motorto closed 1 year ago

motorto commented 2 years ago

Trying to build from source the libwacom-2.4.0, but the 8th test 8/8 libwacom:all / pytest keeps failling without giving much help.

x86_64-glibc voidlinux

Below is the testlog.txt (I have removed the output of the other tests and only kept the 8th one).

I dont know what else to provide, so if I am missing something please tell me so.

testlog.txt ```text Log of Meson test suite run on 2022-08-03T12:45:44.604501 Inherited environment: SHELL=/bin/sh XBPS_ENDIAN=le XBPS_TARGET_ENDIAN=le XBPS_CFLAGS='-O2 -pipe' KERNEL_SITE=https://www.kernel.org/pub/linux XBPS_UHELPER_XCMD=xbps-uhelper CPPFLAGS_FOR_BUILD='' XBPS_ORIG_MAKEJOBS=4 LDFLAGS_FOR_BUILD='' XBPS_ALLOW_RESTRICTED=yes XBPS_TARGET_WORDSIZE=64 XBPS_CMPVER_CMD='xbps-uhelper cmpver' BUILD_LDFLAGS='' XBPS_VERSION=' 0.59.1 ' CPP=cpp XBPS_WORDSIZE=64 XBPS_SHUTILSDIR=/void-packages/common/xbps-src/shutils LD_FOR_BUILD=ld FREEDESKTOP_SITE=https://freedesktop.org/software XBPS_REMOVE_XCMD=xbps-remove XBPS_RINDEX_XCMD=xbps-rindex BUILD_CXX=c++ FFLAGS='-fstack-clash-protection -mtune=generic -O2 -pipe ' XBPS_SRCDISTDIR=/host/sources XBPS_INSTALL_CMD='xbps-install -c /host/repocache-x86_64' PWD=/builddir/libwacom-2.4.0/build XBPS_BUILDSTYLEDIR=/void-packages/common/build-style SOURCE_DATE_EPOCH=1659500892 XBPS_BUILDHELPERDIR=/void-packages/common/build-helper XBPS_LDFLAGS='' XBPS_MASTERDIR=/ XBPS_DESTDIR=/destdir CFLAGS_FOR_BUILD='-O2 -pipe' XBPS_LIBEXECDIR=/void-packages/common/xbps-src/libexec XBPS_RECONFIGURE_CMD=xbps-reconfigure RUST_BUILD=x86_64-unknown-linux-gnu CXX=g++ CXXFLAGS='-fstack-clash-protection -D_FORTIFY_SOURCE=2 -mtune=generic -O2 -pipe -fdebug-prefix-map=/builddir/libwacom-2.4.0=.' XBPS_RECONFIGURE_XCMD=xbps-reconfigure _=/usr/bin/meson BUILD_CC=cc GNU_SITE=https://ftp.gnu.org/gnu BUILD_FC=gfortran XBPS_TARGET_MACHINE=x86_64 XBPS_QUERY_CMD='xbps-query -c /host/repocache-x86_64' BUILD_FFLAGS='-O2 -pipe' LDFLAGS='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed ' XBPS_CPPFLAGS='' HOME=/tmp LANG=en_US.UTF-8 XBPS_UHELPER_CMD=xbps-uhelper XBPS_DISTDIR=/void-packages DEBIAN_SITE=http://ftp.debian.org/debian/pool CXX_FOR_BUILD=g++ SOURCEFORGE_SITE=https://downloads.sourceforge.net/sourceforge XBPS_LIBC=glibc XBPS_RINDEX_CMD=xbps-rindex XBPS_MAKEJOBS=4 XBPS_BUILDDIR=/builddir CPPFLAGS=' ' BUILD_CXXFLAGS='-O2 -pipe' LD=ld XBPS_CHECK_PKGS=yes CCACHE_BASEDIR=/builddir/libwacom-2.4.0/ GNOME_SITE=https://download.gnome.org/sources CPP_FOR_BUILD=cpp NONGNU_SITE=https://download.savannah.nongnu.org/releases READELF=readelf XBPS_NO_ATOMIC8='' QT_QPA_PLATFORM=offscreen CHROOT_READY=1 FC_FOR_BUILD=gfortran BUILD_CFLAGS='-O2 -pipe' XBPS_TARGET_NO_ATOMIC8='' MOZILLA_SITE=https://ftp.mozilla.org/pub XBPS_HOSTDIR=/host XBPS_GIT_CMD=/usr/bin/chroot-git XBPS_CROSSPFDIR=/void-packages/common/cross-profiles CC_FOR_BUILD=cc IN_CHROOT=1 KDE_SITE=https://download.kde.org/stable XBPS_FFLAGS='-O2 -pipe' FFLAGS_FOR_BUILD='-O2 -pipe' VIDEOLAN_SITE=https://download.videolan.org/pub/videolan XBPS_QUERY_XCMD='xbps-query -c /host/repocache-x86_64' AR=ar AS=as CXXFLAGS_FOR_BUILD='-O2 -pipe' XBPS_ALLOW_CHROOT_BREAKOUT='' SHLVL=3 XBPS_CONFIG_FILE=/etc/xbps/xbps-src.conf XORG_SITE=https://www.x.org/releases/individual NM=nm GCC=cc PKG_CONFIG_FOR_BUILD=/usr/bin/pkg-config BUILD_CPPFLAGS='' RUST_TARGET=x86_64-unknown-linux-gnu XBPS_SRC_VERSION=113 XBPS_REMOVE_CMD=xbps-remove XBPS_ALT_REPOSITORY=libwacom-2.4.0 XBPS_MACHINE=x86_64 PYPI_SITE=https://files.pythonhosted.org/packages/source OBJCOPY=objcopy XBPS_TARGET_LIBC=glibc XBPS_TRIGGERSDIR=/void-packages/srcpkgs/xbps-triggers/files FC=gfortran XBPS_CXXFLAGS='-O2 -pipe' XBPS_TARGET=pkg CPAN_SITE=https://www.cpan.org/modules/by-module STRIP=strip XBPS_DIGEST_CMD=xbps-digest LC_COLLATE=C OBJDUMP=objdump PATH=/usr/bin:/home/cerqueira/.config/rofi/menus:/home/cerqueira/.config/bspwm/scripts/:/home/cerqueira/.local/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/texlive/2022/bin/x86_64-linux:/home/cerqueira/git/void-packages/masterdir/usr/bin XBPS_FETCH_CMD=xbps-fetch CC=cc XBPS_SRCPKGDIR=/void-packages/srcpkgs CFLAGS='-fstack-clash-protection -D_FORTIFY_SOURCE=2 -mtune=generic -O2 -pipe -fdebug-prefix-map=/builddir/libwacom-2.4.0=.' XBPS_COMMONDIR=/void-packages/common BUILD_CPP=cpp XBPS_WRAPPERDIR=/builddir/.xbps-libwacom/wrappers XBPS_CHECKVERS_CMD=xbps-checkvers XBPS_REPOSITORY=/host/binpkgs/libwacom-2.4.0 XBPS_STATEDIR=/builddir/.xbps-libwacom XBPS_ARCH=x86_64 XBPS_INSTALL_XCMD='xbps-install -c /host/repocache-x86_64' RANLIB=ranlib UBUNTU_SITE=http://archive.ubuntu.com/ubuntu/pool OLDPWD=/builddir/libwacom-2.4.0 BUILD_LD=ld PKG_CONFIG=pkg-config 1/8 libwacom:all / files-in-git SKIP 0.02s exit status 77 12:45:44 MALLOC_PERTURB_=254 /builddir/libwacom-2.4.0/test/check-files-in-git.sh /builddir/libwacom-2.4.0 ----------------------------------- output ----------------------------------- Not a git tree. Skipping ------------------------------------------------------------------------------ 8/8 libwacom:all / pytest TIMEOUT 30.01s killed by signal 15 SIGTERM 12:45:44 MALLOC_PERTURB_=154 MESON_SOURCE_ROOT=/builddir/libwacom-2.4.0 /usr/bin/pytest /builddir/libwacom-2.4.0 ----------------------------------- output ----------------------------------- ============================= test session starts ============================== platform linux -- Python 3.10.5, pytest-7.1.2, pluggy-1.0.0 rootdir: /builddir/libwacom-2.4.0 collected 1796 items ../test/test_data_files.py ............................................. [ 2%] ........................................................................ [ 6%] ........................................................................ [ 10%] ........................................................................ [ 14%] ........................................................................ [ 18%] ........................................................................ [ 22%] ........................................................................ [ 26%] ........................................................................ [ 30%] ........................................................................ [ 34%] ........................................................................ [ 38%] ........................................................................ [ 42%] ........................................................................ [ 46%] ........................................................................ [ 50%] ........................................................................ [ 54%] ........................................................................ [ 58%] ........................................................................ [ 62%] ........................................................................ [ 66%] ........................................................................ [ 70%] ........................................................................ [ 74%] ................................................................... [ 78%] ../test/test_udev_rules.py EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE [ 80%] EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE [ 84%] EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE [ 88%] EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE [ 92%] EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE [ 96%] EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE ------------------------------------------------------------------------------ Summary of Failures: 8/8 libwacom:all / pytest TIMEOUT 30.01s killed by signal 15 SIGTERM Ok: 6 Expected Fail: 0 Fail: 0 Unexpected Pass: 0 Skipped: 1 Timeout: 1 ```
whot commented 2 years ago

If you run pytest -vv then it should give you better output and at least list the tests that fail. I've added this to meson now in #517, but you can run it manually too.

But it looks like these are all the udev tests that are failing. Do you have an alternative udev installed? Can't remember what void does by default. The test itself is very (too?) simple, see the code, so if you're not running a stock standard udev installation, there are probably cracks to fall through. Happy to fix these where necessary.

motorto commented 2 years ago

Void Linux is using eudev. so it should be fine I think. I will try to debug the test and see where it fails (it seems to timeout after 30 secs)

Apteryks commented 2 years ago

I suspect Void Linux, like GNU Guix, is not a systemd distribution. On GNU Guix the udev tests fail like so:

$ pytest -vv -k 'test_hwdb_files[tablet0]' test/test_udev_rules.py 
=============================================================================================== test session starts ================================================================================================
platform linux -- Python 3.9.9, pytest-6.2.5, py-1.10.0, pluggy-0.13.1 -- /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python
cachedir: .pytest_cache
hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('/tmp/guix-build-libwacom-2.4.0.drv-0/libwacom-2.4.0/.hypothesis/examples')
rootdir: /tmp/guix-build-libwacom-2.4.0.drv-0/libwacom-2.4.0
plugins: hypothesis-6.0.2
collected 388 items / 387 deselected / 1 selected                                                                                                                                                                  

test/test_udev_rules.py::test_hwdb_files[tablet0] ERROR                                                                                                                                                      [100%]

====================================================================================================== ERRORS ======================================================================================================
____________________________________________________________________________________ ERROR at setup of test_hwdb_files[tablet0] ____________________________________________________________________________________

    @pytest.fixture(scope='session', autouse=True)
    def systemd_reload():
        '''Make sure our hwdb and udev rules are up-to-date'''
        import subprocess
>       subprocess.run(['systemd-hwdb', 'update'])

test/test_udev_rules.py:26: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/subprocess.py:505: in run
    with Popen(*popenargs, **kwargs) as process:
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/subprocess.py:951: in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Popen: returncode: 255 args: ['systemd-hwdb', 'update']>, args = ['systemd-hwdb', 'update'], executable = b'systemd-hwdb', preexec_fn = None, close_fds = True, pass_fds = (), cwd = None, env = None
startupinfo = None, creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = -1, c2pwrite = -1, errread = -1, errwrite = -1, restore_signals = True, gid = None, gids = None, uid = None, umask = -1
start_new_session = False

    def _execute_child(self, args, executable, preexec_fn, close_fds,
                       pass_fds, cwd, env,
                       startupinfo, creationflags, shell,
                       p2cread, p2cwrite,
                       c2pread, c2pwrite,
                       errread, errwrite,
                       restore_signals,
                       gid, gids, uid, umask,
                       start_new_session):
        """Execute program (POSIX version)"""

        if isinstance(args, (str, bytes)):
            args = [args]
        elif isinstance(args, os.PathLike):
            if shell:
                raise TypeError('path-like args is not allowed when '
                                'shell is true')
            args = [args]
        else:
            args = list(args)

        if shell:
            # On Android the default shell is at '/system/gnu/store/4y5m9lb8k3qkb1y9m02sw9w9a6hacd16-bash-minimal-5.1.8/bin/sh'.
            unix_shell = ('/system/gnu/store/4y5m9lb8k3qkb1y9m02sw9w9a6hacd16-bash-minimal-5.1.8/bin/sh' if
                      hasattr(sys, 'getandroidapilevel') else '/gnu/store/4y5m9lb8k3qkb1y9m02sw9w9a6hacd16-bash-minimal-5.1.8/bin/sh')
            args = [unix_shell, "-c"] + args
            if executable:
                args[0] = executable

        if executable is None:
            executable = args[0]

        sys.audit("subprocess.Popen", executable, args, cwd, env)

        if (_USE_POSIX_SPAWN
                and os.path.dirname(executable)
                and preexec_fn is None
                and not close_fds
                and not pass_fds
                and cwd is None
                and (p2cread == -1 or p2cread > 2)
                and (c2pwrite == -1 or c2pwrite > 2)
                and (errwrite == -1 or errwrite > 2)
                and not start_new_session
                and gid is None
                and gids is None
                and uid is None
                and umask < 0):
            self._posix_spawn(args, executable, env, restore_signals,
                              p2cread, p2cwrite,
                              c2pread, c2pwrite,
                              errread, errwrite)
            return

        orig_executable = executable

        # For transferring possible exec failure from child to parent.
        # Data format: "exception name:hex errno:description"
        # Pickle is not used; it is complex and involves memory allocation.
        errpipe_read, errpipe_write = os.pipe()
        # errpipe_write must not be in the standard io 0, 1, or 2 fd range.
        low_fds_to_close = []
        while errpipe_write < 3:
            low_fds_to_close.append(errpipe_write)
            errpipe_write = os.dup(errpipe_write)
        for low_fd in low_fds_to_close:
            os.close(low_fd)
        try:
            try:
                # We must avoid complex work that could involve
                # malloc or free in the child process to avoid
                # potential deadlocks, thus we do all this here.
                # and pass it to fork_exec()

                if env is not None:
                    env_list = []
                    for k, v in env.items():
                        k = os.fsencode(k)
                        if b'=' in k:
                            raise ValueError("illegal environment variable name")
                        env_list.append(k + b'=' + os.fsencode(v))
                else:
                    env_list = None  # Use execv instead of execve.
                executable = os.fsencode(executable)
                if os.path.dirname(executable):
                    executable_list = (executable,)
                else:
                    # This matches the behavior of os._execvpe().
                    executable_list = tuple(
                        os.path.join(os.fsencode(dir), executable)
                        for dir in os.get_exec_path(env))
                fds_to_keep = set(pass_fds)
                fds_to_keep.add(errpipe_write)
                self.pid = _posixsubprocess.fork_exec(
                        args, executable_list,
                        close_fds, tuple(sorted(map(int, fds_to_keep))),
                        cwd, env_list,
                        p2cread, p2cwrite, c2pread, c2pwrite,
                        errread, errwrite,
                        errpipe_read, errpipe_write,
                        restore_signals, start_new_session,
                        gid, gids, uid, umask,
                        preexec_fn)
                self._child_created = True
            finally:
                # be sure the FD is closed no matter what
                os.close(errpipe_write)

            self._close_pipe_fds(p2cread, p2cwrite,
                                 c2pread, c2pwrite,
                                 errread, errwrite)

            # Wait for exec to fail or succeed; possibly raising an
            # exception (limited in size)
            errpipe_data = bytearray()
            while True:
                part = os.read(errpipe_read, 50000)
                errpipe_data += part
                if not part or len(errpipe_data) > 50000:
                    break
        finally:
            # be sure the FD is closed no matter what
            os.close(errpipe_read)

        if errpipe_data:
            try:
                pid, sts = os.waitpid(self.pid, 0)
                if pid == self.pid:
                    self._handle_exitstatus(sts)
                else:
                    self.returncode = sys.maxsize
            except ChildProcessError:
                pass

            try:
                exception_name, hex_errno, err_msg = (
                        errpipe_data.split(b':', 2))
                # The encoding here should match the encoding
                # written in by the subprocess implementations
                # like _posixsubprocess
                err_msg = err_msg.decode()
            except ValueError:
                exception_name = b'SubprocessError'
                hex_errno = b'0'
                err_msg = 'Bad exception data from child: {!r}'.format(
                              bytes(errpipe_data))
            child_exception_type = getattr(
                    builtins, exception_name.decode('ascii'),
                    SubprocessError)
            if issubclass(child_exception_type, OSError) and hex_errno:
                errno_num = int(hex_errno, 16)
                child_exec_never_called = (err_msg == "noexec")
                if child_exec_never_called:
                    err_msg = ""
                    # The error must be from chdir(cwd).
                    err_filename = cwd
                else:
                    err_filename = orig_executable
                if errno_num != 0:
                    err_msg = os.strerror(errno_num)
>               raise child_exception_type(errno_num, err_msg, err_filename)
E               FileNotFoundError: [Errno 2] No such file or directory: 'systemd-hwdb'

/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/subprocess.py:1821: FileNotFoundError

I'll try neutralizing that autouse fixture, it may not be necessary.

Apteryks commented 2 years ago

After turning the missing commands in the system_reload fixture to true to neutralize them, all the udev tests were skipped. Removing the exception handling, this is the reason:

test/test_udev_rules.py::test_hwdb_files[tablet0] ERROR                                                                                                                                                      [100%]

====================================================================================================== ERRORS ======================================================================================================
____________________________________________________________________________________ ERROR at setup of test_hwdb_files[tablet0] ____________________________________________________________________________________

tablet = <test_udev_rules.pytest_generate_tests.<locals>.Tablet object at 0x7f9de1819100>

    @pytest.fixture
    def uinput(tablet):
        dev = libevdev.Device()
        dev.name = tablet.name
        dev.id = {
            'vendor': tablet.vid,
            'product': tablet.pid,
            'bustype': tablet.bus
        }
        # Our rules match on pid/vid, so purposely make this look like a
        # non-tablet to verify that our rules apply anyway and not others
        dev.enable(libevdev.EV_REL.REL_X)
        dev.enable(libevdev.EV_REL.REL_Y)
        dev.enable(libevdev.EV_KEY.BTN_LEFT)
        dev.enable(libevdev.EV_KEY.BTN_RIGHT)

>       uinput = dev.create_uinput_device()

test/test_udev_rules.py:101: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/gnu/store/fgay3vpx55ky2ma8ypv1rsplamwcgp1q-python-libevdev-0.11/lib/python3.9/site-packages/libevdev/device.py:764: in create_uinput_device
    d._uinput = UinputDevice(self._libevdev, uinput_fd)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <libevdev._clib.UinputDevice object at 0x7f9de1646730>, source = <libevdev._clib.Libevdev object at 0x7f9de1646340>, fileobj = None

    def __init__(self, source, fileobj=None):
        """
        Create a new uinput device based on the source libevdev device. The
        uinput device will mirror all capabilities from the source device.

        :param source: A libevdev device with all capabilities set.
        :param fileobj: A file-like object to the /dev/uinput node. If None,
        libevdev will open the device in managed mode. See the libevdev
        documentation for details.
        """
        super(UinputDevice, self).__init__()

        self._fileobj = fileobj
        if fileobj is None:
            fd = -2  # UINPUT_OPEN_MANAGED
        else:
            fd = fileobj.fileno()

        self._uinput_device = ctypes.POINTER(_UinputDevice)()
        rc = self._uinput_create_from_device(source._ctx, fd, ctypes.byref(self._uinput_device))
        if rc != 0:
>           raise OSError(-rc, os.strerror(-rc))
E           PermissionError: [Errno 13] Permission denied

/gnu/store/fgay3vpx55ky2ma8ypv1rsplamwcgp1q-python-libevdev-0.11/lib/python3.9/site-packages/libevdev/_clib.py:964: PermissionError
============================================================================================= short test summary info ==============================================================================================
ERROR test/test_udev_rules.py::test_hwdb_files[tablet0] - PermissionError: [Errno 13] Permission denied

Permission errors. I'll just disable that test for now. I guess the test requires to be run as root, which is not the case in the Guix build container.

whot commented 2 years ago

I guess the test requires to be run as root

yes, the tests need to create uinput devices but the uinput() fixture does raise pytest.skip() where that fails. I don't know why the condition doesn't catch the exception in your case, that'd be one thing to debug first.

And the same is true for the systemd_reload fixture, best to raise pytest.skip where that fails and thus have it autoskip the tests.

Apteryks commented 2 years ago

@whot sorry for being unclear, I was experimenting and had removed the exception handling to see what the exceptions were, curious to see if I could get the test to work instead of just being skipped.

motorto commented 2 years ago

Hum @whot the tests depend on systemd and being root ?

whot commented 2 years ago

effectively yes, the tests depend on being able to create uinput devices and reloading the hwdb. both of those usually require you to be root.

Apteryks commented 2 years ago

OK, about the test being skipped, there is an error after all when not patching anything:

building /gnu/store/9ayyjrxsrs1ac076qq772qwamw4v7dyp-baobab-42.0.drv...
 6/12 accountsservice:accounts-service+libaccountsservice+TestAccountsService / TestAccountsService.test_delete_non_existent_user OK              5.73s
derivation '/gnu/store/3bjcsygshjc3h14vin5q9k2180f0nyka-libwacom-2.4.0.drv' offloaded to 'localhost' failed: build of `/gnu/store/3bjcsygshjc3h14vin5q9k2180f0nyka-libwacom-2.4.0.drv' failed
7/8 libwacom:all / pytest                        FAIL           29.60s   exit status 1
>>> MESON_SOURCE_ROOT=/tmp/guix-build-libwacom-2.4.0.drv-0/libwacom-2.4.0 MALLOC_PERTURB_=8 /gnu/store/7frqm5ijy66f81hr8i1j6791k84lds9w-python-pytest-6.2.5/bin/pytest /tmp/guix-build-libwacom-2.4.0.drv-0/libwacom-2.4.0
――――――――――――――――――――――――――――――――――――― ✀  ―――――――――――――――――――――――――――――――――――――
Listing only the last 100 lines from a long log.
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet289]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet290]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet291]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet292]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet293]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet294]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet295]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet296]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet297]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet298]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet299]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet300]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet301]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet302]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet303]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet304]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet305]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet306]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet307]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet308]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet309]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet310]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet311]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet312]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet313]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet314]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet315]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet316]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet317]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet318]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet319]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet320]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet321]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet322]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet323]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet324]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet325]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet326]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet327]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet328]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet329]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet330]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet331]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet332]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet333]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet334]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet335]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet336]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet337]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet338]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet339]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet340]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet341]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet342]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet343]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet344]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet345]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet346]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet347]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet348]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet349]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet350]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet351]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet352]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet353]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet354]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet355]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet356]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet357]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet358]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet359]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet360]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet361]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet362]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet363]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet364]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet365]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet366]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet367]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet368]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet369]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet370]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet371]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet372]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet373]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet374]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet375]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet376]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet377]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet378]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet379]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet380]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet381]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet382]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet383]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet384]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet385]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet386]
ERROR ../libwacom-2.4.0/test/test_udev_rules.py::test_hwdb_files[tablet387]
====================== 1408 passed, 388 errors in 28.89s =======================

I needed to restablish this patch:

(add-after 'unpack 'fix-tests
(lambda _
  ;; Do not attempt to run systemd-specific commands.
  (substitute* "test/test_udev_rules.py"
    (("(systemd-hwdb|systemctl)")
     "true"))))

To have the problematic tests skipped.

whot commented 2 years ago

the meson testlog would have a more detailed explanation of what's going on, the above is just "it failed" but doesn't include any information. You could run pytest -vv --log-level=DEBUG -x directly to get some more info and reduce the logspam (see the pytest help for those flags).

Apteryks commented 2 years ago

Here's what the failure looks like when I remove my patch:

test/test_udev_rules.py::test_hwdb_files[tablet0] ERROR                  [ 78%]

==================================== ERRORS ====================================
__________________ ERROR at setup of test_hwdb_files[tablet0] __________________

    @pytest.fixture(scope='session', autouse=True)
    def systemd_reload():
        '''Make sure our hwdb and udev rules are up-to-date'''
        import subprocess
>       subprocess.run(['systemd-hwdb', 'update'])

test/test_udev_rules.py:26: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/subprocess.py:505: in run
    with Popen(*popenargs, **kwargs) as process:
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/subprocess.py:951: in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Popen: returncode: 255 args: ['systemd-hwdb', 'update']>
args = ['systemd-hwdb', 'update'], executable = b'systemd-hwdb'
preexec_fn = None, close_fds = True, pass_fds = (), cwd = None, env = None
startupinfo = None, creationflags = 0, shell = False, p2cread = -1
p2cwrite = -1, c2pread = -1, c2pwrite = -1, errread = -1, errwrite = -1
restore_signals = True, gid = None, gids = None, uid = None, umask = -1
start_new_session = False

    def _execute_child(self, args, executable, preexec_fn, close_fds,
                       pass_fds, cwd, env,
                       startupinfo, creationflags, shell,
                       p2cread, p2cwrite,
                       c2pread, c2pwrite,
                       errread, errwrite,
                       restore_signals,
                       gid, gids, uid, umask,
                       start_new_session):
        """Execute program (POSIX version)"""

        if isinstance(args, (str, bytes)):
            args = [args]
        elif isinstance(args, os.PathLike):
            if shell:
                raise TypeError('path-like args is not allowed when '
                                'shell is true')
            args = [args]
        else:
            args = list(args)

        if shell:
            # On Android the default shell is at '/system/gnu/store/4y5m9lb8k3qkb1y9m02sw9w9a6hacd16-bash-minimal-5.1.8/bin/sh'.
            unix_shell = ('/system/gnu/store/4y5m9lb8k3qkb1y9m02sw9w9a6hacd16-bash-minimal-5.1.8/bin/sh' if
                      hasattr(sys, 'getandroidapilevel') else '/gnu/store/4y5m9lb8k3qkb1y9m02sw9w9a6hacd16-bash-minimal-5.1.8/bin/sh')
            args = [unix_shell, "-c"] + args
            if executable:
                args[0] = executable

        if executable is None:
            executable = args[0]

        sys.audit("subprocess.Popen", executable, args, cwd, env)

        if (_USE_POSIX_SPAWN
                and os.path.dirname(executable)
                and preexec_fn is None
                and not close_fds
                and not pass_fds
                and cwd is None
                and (p2cread == -1 or p2cread > 2)
                and (c2pwrite == -1 or c2pwrite > 2)
                and (errwrite == -1 or errwrite > 2)
                and not start_new_session
                and gid is None
                and gids is None
                and uid is None
                and umask < 0):
            self._posix_spawn(args, executable, env, restore_signals,
                              p2cread, p2cwrite,
                              c2pread, c2pwrite,
                              errread, errwrite)
            return

        orig_executable = executable

        # For transferring possible exec failure from child to parent.
        # Data format: "exception name:hex errno:description"
        # Pickle is not used; it is complex and involves memory allocation.
        errpipe_read, errpipe_write = os.pipe()
        # errpipe_write must not be in the standard io 0, 1, or 2 fd range.
        low_fds_to_close = []
        while errpipe_write < 3:
            low_fds_to_close.append(errpipe_write)
            errpipe_write = os.dup(errpipe_write)
        for low_fd in low_fds_to_close:
            os.close(low_fd)
        try:
            try:
                # We must avoid complex work that could involve
                # malloc or free in the child process to avoid
                # potential deadlocks, thus we do all this here.
                # and pass it to fork_exec()

                if env is not None:
                    env_list = []
                    for k, v in env.items():
                        k = os.fsencode(k)
                        if b'=' in k:
                            raise ValueError("illegal environment variable name")
                        env_list.append(k + b'=' + os.fsencode(v))
                else:
                    env_list = None  # Use execv instead of execve.
                executable = os.fsencode(executable)
                if os.path.dirname(executable):
                    executable_list = (executable,)
                else:
                    # This matches the behavior of os._execvpe().
                    executable_list = tuple(
                        os.path.join(os.fsencode(dir), executable)
                        for dir in os.get_exec_path(env))
                fds_to_keep = set(pass_fds)
                fds_to_keep.add(errpipe_write)
                self.pid = _posixsubprocess.fork_exec(
                        args, executable_list,
                        close_fds, tuple(sorted(map(int, fds_to_keep))),
                        cwd, env_list,
                        p2cread, p2cwrite, c2pread, c2pwrite,
                        errread, errwrite,
                        errpipe_read, errpipe_write,
                        restore_signals, start_new_session,
                        gid, gids, uid, umask,
                        preexec_fn)
                self._child_created = True
            finally:
                # be sure the FD is closed no matter what
                os.close(errpipe_write)

            self._close_pipe_fds(p2cread, p2cwrite,
                                 c2pread, c2pwrite,
                                 errread, errwrite)

            # Wait for exec to fail or succeed; possibly raising an
            # exception (limited in size)
            errpipe_data = bytearray()
            while True:
                part = os.read(errpipe_read, 50000)
                errpipe_data += part
                if not part or len(errpipe_data) > 50000:
                    break
        finally:
            # be sure the FD is closed no matter what
            os.close(errpipe_read)

        if errpipe_data:
            try:
                pid, sts = os.waitpid(self.pid, 0)
                if pid == self.pid:
                    self._handle_exitstatus(sts)
                else:
                    self.returncode = sys.maxsize
            except ChildProcessError:
                pass

            try:
                exception_name, hex_errno, err_msg = (
                        errpipe_data.split(b':', 2))
                # The encoding here should match the encoding
                # written in by the subprocess implementations
                # like _posixsubprocess
                err_msg = err_msg.decode()
            except ValueError:
                exception_name = b'SubprocessError'
                hex_errno = b'0'
                err_msg = 'Bad exception data from child: {!r}'.format(
                              bytes(errpipe_data))
            child_exception_type = getattr(
                    builtins, exception_name.decode('ascii'),
                    SubprocessError)
            if issubclass(child_exception_type, OSError) and hex_errno:
                errno_num = int(hex_errno, 16)
                child_exec_never_called = (err_msg == "noexec")
                if child_exec_never_called:
                    err_msg = ""
                    # The error must be from chdir(cwd).
                    err_filename = cwd
                else:
                    err_filename = orig_executable
                if errno_num != 0:
                    err_msg = os.strerror(errno_num)
>               raise child_exception_type(errno_num, err_msg, err_filename)
E               FileNotFoundError: [Errno 2] No such file or directory: 'systemd-hwdb'

/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/subprocess.py:1821: FileNotFoundError
=========================== short test summary info ============================
ERROR test/test_udev_rules.py::test_hwdb_files[tablet0] - FileNotFoundError: ...
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
======================== 1408 passed, 1 error in 1.65s =========================
error: in phase 'check': uncaught exception:
%exception #<&invoke-error program: "pytest" arguments: ("-vv" "--log-level=DEBUG" "-x") exit-status: 1 term-signal: #f stop-signal: #f> 
whot commented 2 years ago

subprocess.run(['systemd-hwdb', 'update'])

this runs systemd-hwdb, guess we need some check for that to exist and raise a skip exception if not. Happy to take a PR for that.