mirror of
https://github.com/clearlinux/graphene.git
synced 2026-09-03 12:21:37 +00:00
Pylint output was filtered so that many files with existing pylint violations were allowed to stay broken. I made sure all files pass pylint, but whitelisted some rules that we commonly disable: * missing docstrings: most of the code is tests/internal anyway * invalid-name: too many violations, and we commonly use one- or two-character names (like "a, b" or "t1, t2") which is disallowed by this rule; we could tweak it and then fix remaining violations such as camel-case or lowercase constants * fixme: we leave TODOs as a matter of practice, same as in C * high-level style rules like too-few-* and too-many-*, no-self-use Hopefully that will make using pylint less annoying, while also catching serious issues (such as unused variables or imports).
140 lines
4.9 KiB
Python
140 lines
4.9 KiB
Python
import contextlib
|
|
import os
|
|
import pathlib
|
|
import signal
|
|
import subprocess
|
|
import sys
|
|
import unittest
|
|
|
|
# pylint: disable=subprocess-popen-preexec-fn,subprocess-run-check
|
|
|
|
HAS_SGX = os.environ.get('SGX') == '1'
|
|
ON_X86 = os.uname().machine in ['x86_64']
|
|
|
|
def expectedFailureIf(predicate):
|
|
if predicate:
|
|
return unittest.expectedFailure
|
|
return lambda func: func
|
|
|
|
class RegressionTestCase(unittest.TestCase):
|
|
LOADER_ENV = 'PAL_LOADER'
|
|
LIBPAL_PATH_ENV = 'LIBPAL_PATH'
|
|
HOST_PAL_PATH_ENV = 'HOST_PAL_PATH'
|
|
DEFAULT_TIMEOUT = (20 if HAS_SGX else 10)
|
|
|
|
def get_manifest(self, filename):
|
|
return filename + '.manifest' + ('.sgx' if HAS_SGX else '')
|
|
|
|
def get_env(self, name):
|
|
try:
|
|
return os.environ[name]
|
|
except KeyError:
|
|
self.fail('environment variable {} not set'.format(name))
|
|
|
|
def has_debug(self):
|
|
libpal = self.get_env(self.LIBPAL_PATH_ENV)
|
|
p = subprocess.run(['objdump', '-x', libpal], check=True, stdout=subprocess.PIPE)
|
|
dump = p.stdout.decode()
|
|
return '.debug_info' in dump
|
|
|
|
def run_gdb(self, args, gdb_script, **kwds):
|
|
host_pal_path = self.get_env(self.HOST_PAL_PATH_ENV)
|
|
|
|
# See also pal_loader.
|
|
prefix = ['gdb', '-q']
|
|
env = os.environ.copy()
|
|
if HAS_SGX:
|
|
prefix += ['-x', os.path.join(host_pal_path, 'gdb_integration/graphene_sgx_gdb.py')]
|
|
sgx_gdb = os.path.join(host_pal_path, 'gdb_integration/sgx_gdb.so')
|
|
env['LD_PRELOAD'] = sgx_gdb + ':' + env.get('LD_PRELOAD', '')
|
|
else:
|
|
prefix += ['-x', os.path.join(host_pal_path, 'gdb_integration/graphene_gdb.py')]
|
|
|
|
# Override TTY, as apparently os.setpgrp() confuses GDB and causes it to hang.
|
|
prefix += ['-x', gdb_script, '-batch', '-tty=/dev/null']
|
|
prefix += ['--args']
|
|
|
|
return self.run_binary(args, prefix=prefix, env=env, **kwds)
|
|
|
|
def run_binary(self, args, *, timeout=None, prefix=None, **kwds):
|
|
timeout = (max(self.DEFAULT_TIMEOUT, timeout) if timeout is not None
|
|
else self.DEFAULT_TIMEOUT)
|
|
|
|
loader = self.get_env(self.LOADER_ENV)
|
|
if not pathlib.Path(loader).exists():
|
|
self.skipTest('loader ({}) not found'.format(loader))
|
|
|
|
libpal = self.get_env(self.LIBPAL_PATH_ENV)
|
|
if not pathlib.Path(libpal).exists():
|
|
self.skipTest('libpal ({}) not found'.format(libpal))
|
|
|
|
if prefix is None:
|
|
prefix = []
|
|
|
|
with subprocess.Popen([*prefix, loader, libpal, 'init', *args],
|
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
preexec_fn=os.setpgrp,
|
|
**kwds) as process:
|
|
try:
|
|
stdout, stderr = process.communicate(timeout=timeout)
|
|
except subprocess.TimeoutExpired:
|
|
os.killpg(process.pid, signal.SIGKILL)
|
|
self.fail('timeout ({} s) expired'.format(timeout))
|
|
|
|
self.print_output(stdout, stderr)
|
|
|
|
if process.returncode:
|
|
raise subprocess.CalledProcessError(
|
|
process.returncode, args, stdout, stderr)
|
|
|
|
return stdout.decode(), stderr.decode()
|
|
|
|
@classmethod
|
|
def run_native_binary(cls, args, timeout=None, libpath=None, **kwds):
|
|
timeout = (max(cls.DEFAULT_TIMEOUT, timeout) if timeout is not None
|
|
else cls.DEFAULT_TIMEOUT)
|
|
|
|
my_env = os.environ.copy()
|
|
if not libpath is None:
|
|
my_env["LD_LIBRARY_PATH"] = libpath
|
|
|
|
with subprocess.Popen(args,
|
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
env=my_env,
|
|
preexec_fn=os.setpgrp,
|
|
**kwds) as process:
|
|
try:
|
|
stdout, stderr = process.communicate(timeout=timeout)
|
|
except subprocess.TimeoutExpired:
|
|
os.killpg(process.pid, signal.SIGKILL)
|
|
raise AssertionError('timeout ({} s) expired'.format(timeout))
|
|
|
|
cls.print_output(stdout, stderr)
|
|
|
|
if process.returncode:
|
|
raise subprocess.CalledProcessError(
|
|
process.returncode, args, stdout, stderr)
|
|
|
|
return stdout.decode(), stderr.decode()
|
|
|
|
@staticmethod
|
|
def print_output(stdout: bytes, stderr: bytes):
|
|
'''
|
|
Print command output (stdout, stderr) so that pytest can capture it.
|
|
'''
|
|
|
|
sys.stdout.write(stdout.decode(errors='surrogateescape'))
|
|
sys.stderr.write(stderr.decode(errors='surrogateescape'))
|
|
|
|
@contextlib.contextmanager
|
|
def expect_returncode(self, returncode):
|
|
if returncode == 0:
|
|
raise ValueError('expected returncode should be nonzero')
|
|
try:
|
|
yield
|
|
self.fail('did not fail (expected {})'.format(returncode))
|
|
except subprocess.CalledProcessError as e:
|
|
self.assertEqual(e.returncode, returncode,
|
|
'failed with returncode {} (expected {})'.format(
|
|
e.returncode, returncode))
|