mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-07-30 05:32:30 +08:00
132 lines
4.2 KiB
Python
132 lines
4.2 KiB
Python
"""
|
|
subprocesstest enables unittest test cases and suites to be run in separate
|
|
python interpreter instances.
|
|
|
|
A base class SubprocessTestCase is provided that, when extended, will run test
|
|
cases marked with @run_in_subprocess in a separate python interpreter.
|
|
"""
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import unittest
|
|
|
|
|
|
SUBPROC_TEST_ATTR = '_subproc_test'
|
|
SUBPROC_ENV_VAR = 'SUBPROCESS_TEST'
|
|
|
|
|
|
def run_in_subprocess(obj):
|
|
"""
|
|
Marks a test case that is to be run in its own 'clean' interpreter instance.
|
|
|
|
When applied to a TestCase class, each method will be run in a separate
|
|
interpreter instance.
|
|
|
|
Usage on a class::
|
|
|
|
from tests.subprocesstest import SubprocessTestCase, run_in_subprocess
|
|
|
|
@run_in_subprocess
|
|
class PatchTests(SubprocessTestCase):
|
|
# will be run in new interpreter
|
|
def test_patch_before_import(self):
|
|
patch()
|
|
import module
|
|
|
|
# will be run in new interpreter as well
|
|
def test_patch_after_import(self):
|
|
import module
|
|
patch()
|
|
|
|
|
|
Usage on a test method::
|
|
|
|
class OtherTests(SubprocessTestCase):
|
|
@run_in_subprocess
|
|
def test_case(self):
|
|
pass
|
|
|
|
|
|
:param obj: method or class to run in a separate python interpreter.
|
|
:return:
|
|
"""
|
|
setattr(obj, SUBPROC_TEST_ATTR, True)
|
|
return obj
|
|
|
|
|
|
class SubprocessTestCase(unittest.TestCase):
|
|
def _full_method_name(self):
|
|
test = getattr(self, self._testMethodName)
|
|
# DEV: we have to use the internal self reference of the bound test
|
|
# method to pull out the class and module since using a mix of `self`
|
|
# and the test attributes will result in inconsistencies when the test
|
|
# method is defined on another class.
|
|
# A concrete case of this is a parent and child TestCase where the child
|
|
# doesn't override a parent test method. The full_method_name we want
|
|
# is that of the child test method (even though it exists on the parent)
|
|
modpath = test.__self__.__class__.__module__
|
|
clsname = test.__self__.__class__.__name__
|
|
testname = test.__name__
|
|
testcase_name = '{}.{}.{}'.format(modpath, clsname, testname)
|
|
return testcase_name
|
|
|
|
def _run_test_in_subprocess(self, result):
|
|
full_testcase_name = self._full_method_name()
|
|
|
|
# copy the environment and include the special subprocess environment
|
|
# variable for the subprocess to detect
|
|
sp_test_env = os.environ.copy()
|
|
sp_test_env[SUBPROC_ENV_VAR] = 'True'
|
|
sp_test_cmd = ['python', '-m', 'unittest', full_testcase_name]
|
|
sp = subprocess.Popen(
|
|
sp_test_cmd,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
env=sp_test_env,
|
|
)
|
|
stdout, stderr = sp.communicate()
|
|
|
|
if sp.returncode:
|
|
try:
|
|
cmdf = ' '.join(sp_test_cmd)
|
|
raise Exception('Subprocess Test "{}" Failed'.format(cmdf))
|
|
except Exception:
|
|
exc_info = sys.exc_info()
|
|
|
|
# DEV: stderr, stdout are byte sequences so to print them nicely
|
|
# back out they should be decoded.
|
|
sys.stderr.write(stderr.decode())
|
|
sys.stdout.write(stdout.decode())
|
|
result.addFailure(self, exc_info)
|
|
else:
|
|
result.addSuccess(self)
|
|
|
|
def _in_subprocess(self):
|
|
"""Determines if the test is being run in a subprocess.
|
|
|
|
This is done by checking for an environment variable that we call the
|
|
subprocess test with.
|
|
|
|
:return: whether the test is a subprocess test
|
|
"""
|
|
return os.getenv(SUBPROC_ENV_VAR, None) is not None
|
|
|
|
def _is_subprocess_test(self):
|
|
if hasattr(self, SUBPROC_TEST_ATTR):
|
|
return True
|
|
|
|
test = getattr(self, self._testMethodName)
|
|
if hasattr(test, SUBPROC_TEST_ATTR):
|
|
return True
|
|
|
|
return False
|
|
|
|
def run(self, result=None):
|
|
if not self._is_subprocess_test():
|
|
return super(SubprocessTestCase, self).run(result=result)
|
|
|
|
if self._in_subprocess():
|
|
return super(SubprocessTestCase, self).run(result=result)
|
|
else:
|
|
self._run_test_in_subprocess(result)
|