xref: /src/tests/atf_python/utils.py (revision 7659d0fa2b873374623e7582e38fb2fe92056c87)
13873bdc2SAlexander V. Chernikov#!/usr/bin/env python3
23873bdc2SAlexander V. Chernikovimport os
36332ef89SAlexander V. Chernikovimport pwd
43873bdc2SAlexander V. Chernikovfrom ctypes import CDLL
53873bdc2SAlexander V. Chernikovfrom ctypes import get_errno
63873bdc2SAlexander V. Chernikovfrom ctypes.util import find_library
76332ef89SAlexander V. Chernikovfrom typing import Dict
83873bdc2SAlexander V. Chernikovfrom typing import List
93873bdc2SAlexander V. Chernikovfrom typing import Optional
103873bdc2SAlexander V. Chernikov
113873bdc2SAlexander V. Chernikovimport pytest
123873bdc2SAlexander V. Chernikov
133873bdc2SAlexander V. Chernikov
14d9af4219SAlexander V. Chernikovdef nodeid_to_method_name(nodeid: str) -> str:
15d9af4219SAlexander V. Chernikov    """file_name.py::ClassName::method_name[parametrize] -> method_name"""
16d9af4219SAlexander V. Chernikov    return nodeid.split("::")[-1].split("[")[0]
17d9af4219SAlexander V. Chernikov
18d9af4219SAlexander V. Chernikov
193873bdc2SAlexander V. Chernikovclass LibCWrapper(object):
203873bdc2SAlexander V. Chernikov    def __init__(self):
213873bdc2SAlexander V. Chernikov        path: Optional[str] = find_library("c")
223873bdc2SAlexander V. Chernikov        if path is None:
233873bdc2SAlexander V. Chernikov            raise RuntimeError("libc not found")
243873bdc2SAlexander V. Chernikov        self._libc = CDLL(path, use_errno=True)
253873bdc2SAlexander V. Chernikov
263873bdc2SAlexander V. Chernikov    def modfind(self, mod_name: str) -> int:
273873bdc2SAlexander V. Chernikov        if self._libc.modfind(bytes(mod_name, encoding="ascii")) == -1:
283873bdc2SAlexander V. Chernikov            return get_errno()
293873bdc2SAlexander V. Chernikov        return 0
303873bdc2SAlexander V. Chernikov
313e5d0784SAlexander V. Chernikov    def kldload(self, kld_name: str) -> int:
323e5d0784SAlexander V. Chernikov        if self._libc.kldload(bytes(kld_name, encoding="ascii")) == -1:
333e5d0784SAlexander V. Chernikov            return get_errno()
343e5d0784SAlexander V. Chernikov        return 0
353e5d0784SAlexander V. Chernikov
363873bdc2SAlexander V. Chernikov    def jail_attach(self, jid: int) -> int:
373873bdc2SAlexander V. Chernikov        if self._libc.jail_attach(jid) != 0:
383873bdc2SAlexander V. Chernikov            return get_errno()
393873bdc2SAlexander V. Chernikov        return 0
403873bdc2SAlexander V. Chernikov
413873bdc2SAlexander V. Chernikov
423873bdc2SAlexander V. Chernikovlibc = LibCWrapper()
433873bdc2SAlexander V. Chernikov
443873bdc2SAlexander V. Chernikov
453873bdc2SAlexander V. Chernikovclass BaseTest(object):
466332ef89SAlexander V. Chernikov    NEED_ROOT: bool = False  # True if the class needs root privileges for the setup
476332ef89SAlexander V. Chernikov    TARGET_USER = None  # Set to the target user by the framework
483873bdc2SAlexander V. Chernikov    REQUIRED_MODULES: List[str] = []
497659d0faSKristof Provost    SKIP_MODULES: List[str] = []
503873bdc2SAlexander V. Chernikov
5197760572SAlexander V. Chernikov    def require_module(self, mod_name: str, skip=True):
5297760572SAlexander V. Chernikov        error_code = libc.modfind(mod_name)
5397760572SAlexander V. Chernikov        if error_code == 0:
5497760572SAlexander V. Chernikov            return
5597760572SAlexander V. Chernikov        err_str = os.strerror(error_code)
5697760572SAlexander V. Chernikov        txt = "kernel module '{}' not available: {}".format(mod_name, err_str)
5797760572SAlexander V. Chernikov        if skip:
5897760572SAlexander V. Chernikov            pytest.skip(txt)
5997760572SAlexander V. Chernikov        else:
6097760572SAlexander V. Chernikov            raise ValueError(txt)
6197760572SAlexander V. Chernikov
627659d0faSKristof Provost    def skip_module(self, mod_name: str):
637659d0faSKristof Provost        error_code = libc.modfind(mod_name)
647659d0faSKristof Provost        if error_code == 0:
657659d0faSKristof Provost            txt = "kernel module '{}' loaded, skip test".format(mod_name)
667659d0faSKristof Provost            pytest.skip(txt)
677659d0faSKristof Provost            return
687659d0faSKristof Provost
693873bdc2SAlexander V. Chernikov    def _check_modules(self):
703873bdc2SAlexander V. Chernikov        for mod_name in self.REQUIRED_MODULES:
7197760572SAlexander V. Chernikov            self.require_module(mod_name)
727659d0faSKristof Provost        for mod_name in self.SKIP_MODULES:
737659d0faSKristof Provost            self.skip_module(mod_name)
7497760572SAlexander V. Chernikov
756332ef89SAlexander V. Chernikov    @property
766332ef89SAlexander V. Chernikov    def atf_vars(self) -> Dict[str, str]:
776332ef89SAlexander V. Chernikov        px = "_ATF_VAR_"
786332ef89SAlexander V. Chernikov        return {k[len(px):]: v for k, v in os.environ.items() if k.startswith(px)}
796332ef89SAlexander V. Chernikov
806332ef89SAlexander V. Chernikov    def drop_privileges_user(self, user: str):
816332ef89SAlexander V. Chernikov        uid = pwd.getpwnam(user)[2]
826332ef89SAlexander V. Chernikov        print("Dropping privs to {}/{}".format(user, uid))
836332ef89SAlexander V. Chernikov        os.setuid(uid)
846332ef89SAlexander V. Chernikov
856332ef89SAlexander V. Chernikov    def drop_privileges(self):
866332ef89SAlexander V. Chernikov        if self.TARGET_USER:
876332ef89SAlexander V. Chernikov            if self.TARGET_USER == "unprivileged":
886332ef89SAlexander V. Chernikov                user = self.atf_vars["unprivileged-user"]
896332ef89SAlexander V. Chernikov            else:
906332ef89SAlexander V. Chernikov                user = self.TARGET_USER
916332ef89SAlexander V. Chernikov            self.drop_privileges_user(user)
923873bdc2SAlexander V. Chernikov
93f63825ffSAlexander V. Chernikov    @property
946332ef89SAlexander V. Chernikov    def test_id(self) -> str:
95f63825ffSAlexander V. Chernikov        # 'test_ip6_output.py::TestIP6Output::test_output6_pktinfo[ipandif] (setup)'
96f63825ffSAlexander V. Chernikov        return os.environ.get("PYTEST_CURRENT_TEST").split(" ")[0]
97f63825ffSAlexander V. Chernikov
98f63825ffSAlexander V. Chernikov    def setup_method(self, method):
99f63825ffSAlexander V. Chernikov        """Run all pre-requisits for the test execution"""
1003873bdc2SAlexander V. Chernikov        self._check_modules()
101