from pyroute2 import NSPopen import traceback import shutil import logging, os, sys, re if 'PYTHON_TEST_LOGFILE' in os.environ: logfile=os.environ['PYTHON_TEST_LOGFILE'] logging.basicConfig(level=logging.ERROR, filename=logfile, filemode='a') else: logging.basicConfig(level=logging.ERROR, stream=sys.stderr) logger = logging.getLogger() def has_executable(name): path = shutil.which(name) if path is None: raise Exception(name + ": command not found") return path # This is a decorator that will allow for logging tests, but flagging them as # "known to fail". These tests legitimately fail and represent actual bugs, but # as these are already documented the test status can be "green" without these # tests, similar to catch2's [!mayfail] tag. # This is done using the existing python unittest concept of an "expected failure", # but it is only done after the fact, if the test fails or raises an exception. # It gives all tests a chance to succeed, but if they fail it logs them and # continues. def mayFail(message): def decorator(func): def wrapper(*args, **kwargs): res = None err = None try: res = func(*args, **kwargs) except BaseException as e: logger.critical("WARNING! Test %s failed, but marked as passed because it is decorated with @mayFail." % args[0]) logger.critical("\tThe reason why this mayFail was: %s" % message) logger.critical("\tThe failure was: \"%s\"" % e) logger.critical("\tStacktrace: \"%s\"" % traceback.format_exc()) testcase=args[0] testcase.TestResult().addExpectedFailure(testcase, e) err = e finally: if err != None: raise err else: return res return wrapper return decorator # This is a decorator that will skip tests if any binary in the list is not in PATH. def skipUnlessHasBinaries(binaries, message): def decorator(func): def wrapper(self, *args, **kwargs): missing = [] for binary in binaries: if shutil.which(binary) is None: missing.append(binary) if len(missing): missing_binaries = ", ".join(missing) self.skipTest(f"Missing binaries: {missing_binaries}. {message}") else: func(self, *args, **kwargs) return wrapper return decorator class NSPopenWithCheck(NSPopen): """ A wrapper for NSPopen that additionally checks if the program to be executed is available from the system path or not. If found, it proceeds with the usual NSPopen() call. Otherwise, it raises an exception. """ def __init__(self, nsname, *argv, **kwarg): name = list(argv)[0][0] has_executable(name) super(NSPopenWithCheck, self).__init__(nsname, *argv, **kwarg) KERNEL_VERSION_PATTERN = r"v?(?P[0-9]+)\.(?P[0-9]+).*" def kernel_version_ge(major, minor): # True if running kernel is >= X.Y match = re.match(KERNEL_VERSION_PATTERN, os.uname()[2]) x = int(match.group("major")) y = int(match.group("minor")) if x > major: return True if x < major: return False if minor and y < minor: return False return True