aboutsummaryrefslogtreecommitdiffstats
path: root/library/python/pytest
diff options
context:
space:
mode:
authorDmitry Kopylov <kopylovd@gmail.com>2022-02-10 16:48:18 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:48:18 +0300
commit7230275728d34873cba1ba78bb68669b0c5faa31 (patch)
treeb222e5ac2e2e98872661c51ccceee5da0d291e13 /library/python/pytest
parentb2f5101486cc0de2e979c8ba9ada2109785bf5fd (diff)
downloadydb-7230275728d34873cba1ba78bb68669b0c5faa31.tar.gz
Restoring authorship annotation for Dmitry Kopylov <kopylovd@gmail.com>. Commit 2 of 2.
Diffstat (limited to 'library/python/pytest')
-rw-r--r--library/python/pytest/allure/conftest.py16
-rw-r--r--library/python/pytest/empty/main.c14
-rw-r--r--library/python/pytest/empty/ya.make10
-rw-r--r--library/python/pytest/main.py38
-rw-r--r--library/python/pytest/plugins/collection.py70
-rw-r--r--library/python/pytest/plugins/conftests.py38
-rw-r--r--library/python/pytest/plugins/fixtures.py120
-rw-r--r--library/python/pytest/plugins/ya.make28
-rw-r--r--library/python/pytest/plugins/ya.py862
-rw-r--r--library/python/pytest/pytest.yatest.ini4
-rw-r--r--library/python/pytest/ya.make28
-rw-r--r--library/python/pytest/yatest_tools.py262
12 files changed, 745 insertions, 745 deletions
diff --git a/library/python/pytest/allure/conftest.py b/library/python/pytest/allure/conftest.py
index 451e377cfc..0d5cfda1e5 100644
--- a/library/python/pytest/allure/conftest.py
+++ b/library/python/pytest/allure/conftest.py
@@ -1,8 +1,8 @@
-import os
-import pytest
-
-
-@pytest.mark.tryfirst
-def pytest_configure(config):
- if "ALLURE_REPORT_DIR" in os.environ:
- config.option.allurereportdir = os.environ["ALLURE_REPORT_DIR"]
+import os
+import pytest
+
+
+@pytest.mark.tryfirst
+def pytest_configure(config):
+ if "ALLURE_REPORT_DIR" in os.environ:
+ config.option.allurereportdir = os.environ["ALLURE_REPORT_DIR"]
diff --git a/library/python/pytest/empty/main.c b/library/python/pytest/empty/main.c
index d49fcc7031..9efa08162a 100644
--- a/library/python/pytest/empty/main.c
+++ b/library/python/pytest/empty/main.c
@@ -1,7 +1,7 @@
-/*
-to be used for build python tests in a stub binary for the case of using system python
-*/
-
-int main(void) {
- return 0;
-}
+/*
+to be used for build python tests in a stub binary for the case of using system python
+*/
+
+int main(void) {
+ return 0;
+}
diff --git a/library/python/pytest/empty/ya.make b/library/python/pytest/empty/ya.make
index 4394568f15..8f0fa37e2a 100644
--- a/library/python/pytest/empty/ya.make
+++ b/library/python/pytest/empty/ya.make
@@ -1,12 +1,12 @@
-LIBRARY()
-
+LIBRARY()
+
OWNER(
g:yatool
dmitko
)
-
+
SRCS(
main.c
)
-
-END()
+
+END()
diff --git a/library/python/pytest/main.py b/library/python/pytest/main.py
index df3513031f..6296bd6f0f 100644
--- a/library/python/pytest/main.py
+++ b/library/python/pytest/main.py
@@ -1,25 +1,25 @@
import os
-import sys
+import sys
import time
import __res
-
+
FORCE_EXIT_TESTSFAILED_ENV = 'FORCE_EXIT_TESTSFAILED'
-def main():
+def main():
import library.python.pytest.context as context
context.Ctx["YA_PYTEST_START_TIMESTAMP"] = time.time()
profile = None
if '--profile-pytest' in sys.argv:
sys.argv.remove('--profile-pytest')
-
+
import pstats
import cProfile
profile = cProfile.Profile()
profile.enable()
-
+
# Reset influencing env. vars
# For more info see library/python/testing/yatest_common/yatest/common/errors.py
if FORCE_EXIT_TESTSFAILED_ENV in os.environ:
@@ -46,12 +46,12 @@ def main():
m.setattr(_pytest.assertion.rewrite, "AssertionRewritingHook", rewrite.AssertionRewritingHook)
prefix = '__tests__.'
-
+
test_modules = [
name[len(prefix):] for name in sys.extra_modules
if name.startswith(prefix) and not name.endswith('.conftest')
]
-
+
doctest_packages = __res.find("PY_DOCTEST_PACKAGES") or ""
if isinstance(doctest_packages, bytes):
doctest_packages = doctest_packages.decode('utf-8')
@@ -70,20 +70,20 @@ def main():
def remove_user_site(paths):
site_paths = ('site-packages', 'site-python')
-
+
def is_site_path(path):
for p in site_paths:
if path.find(p) != -1:
return True
return False
-
+
new_paths = list(paths)
for p in paths:
if is_site_path(p):
new_paths.remove(p)
-
+
return new_paths
-
+
sys.path = remove_user_site(sys.path)
rc = pytest.main(plugins=[
collection.CollectionPlugin(test_modules, doctest_modules),
@@ -91,10 +91,10 @@ def main():
conftests,
])
- if rc == 5:
- # don't care about EXIT_NOTESTSCOLLECTED
- rc = 0
-
+ if rc == 5:
+ # don't care about EXIT_NOTESTSCOLLECTED
+ rc = 0
+
if rc == 1 and yatest_runner and not listing_mode and not os.environ.get(FORCE_EXIT_TESTSFAILED_ENV) == '1':
# XXX it's place for future improvements
# Test wrapper should terminate with 0 exit code if there are common test failures
@@ -110,7 +110,7 @@ def main():
ps.print_stats()
sys.exit(rc)
-
-
-if __name__ == '__main__':
- main()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/library/python/pytest/plugins/collection.py b/library/python/pytest/plugins/collection.py
index 1535da686c..e36f47a78f 100644
--- a/library/python/pytest/plugins/collection.py
+++ b/library/python/pytest/plugins/collection.py
@@ -1,26 +1,26 @@
import os
-import sys
+import sys
from six import reraise
-
-import py
+
+import py
import pytest # noqa
-import _pytest.python
-import _pytest.doctest
+import _pytest.python
+import _pytest.doctest
import json
import library.python.testing.filter.filter as test_filter
-
-
-class LoadedModule(_pytest.python.Module):
+
+
+class LoadedModule(_pytest.python.Module):
def __init__(self, parent, name, **kwargs):
self.name = name + '.py'
self.session = parent
self.parent = parent
self.config = parent.config
- self.keywords = {}
+ self.keywords = {}
self.own_markers = []
self.fspath = py.path.local()
-
+
@classmethod
def from_parent(cls, **kwargs):
namespace = kwargs.pop('namespace', True)
@@ -31,7 +31,7 @@ class LoadedModule(_pytest.python.Module):
return loaded_module
- @property
+ @property
def _nodeid(self):
if os.getenv('CONFTEST_LOAD_POLICY') == 'LOCAL':
return self._getobj().__file__
@@ -41,25 +41,25 @@ class LoadedModule(_pytest.python.Module):
@property
def nodeid(self):
return self._nodeid
-
- def _getobj(self):
+
+ def _getobj(self):
module_name = self.name[:-len('.py')]
if self.namespace:
module_name = '__tests__.' + module_name
- __import__(module_name)
- return sys.modules[module_name]
-
-
-class DoctestModule(LoadedModule):
-
- def collect(self):
- import doctest
+ __import__(module_name)
+ return sys.modules[module_name]
+
+
+class DoctestModule(LoadedModule):
+
+ def collect(self):
+ import doctest
module = self._getobj()
# uses internal doctest module parsing mechanism
- finder = doctest.DocTestFinder()
- optionflags = _pytest.doctest.get_optionflags(self)
- runner = doctest.DebugRunner(verbose=0, optionflags=optionflags)
+ finder = doctest.DocTestFinder()
+ optionflags = _pytest.doctest.get_optionflags(self)
+ runner = doctest.DebugRunner(verbose=0, optionflags=optionflags)
try:
for test in finder.find(module, self.name[:-len('.py')]):
@@ -75,8 +75,8 @@ class DoctestModule(LoadedModule):
etype, exc, tb = sys.exc_info()
msg = 'DoctestModule failed, probably you can add NO_DOCTESTS() macro to ya.make'
reraise(etype, type(exc)('{}\n{}'.format(exc, msg)), tb)
-
-
+
+
# NOTE: Since we are overriding collect method of pytest session, pytest hooks are not invoked during collection.
def pytest_ignore_collect(module, session, filenames_from_full_filters, accept_filename_predicate):
if session.config.option.mode == 'list':
@@ -93,14 +93,14 @@ def pytest_ignore_collect(module, session, filenames_from_full_filters, accept_f
return False
-class CollectionPlugin(object):
+class CollectionPlugin(object):
def __init__(self, test_modules, doctest_modules):
- self._test_modules = test_modules
+ self._test_modules = test_modules
self._doctest_modules = doctest_modules
-
- def pytest_sessionstart(self, session):
-
- def collect(*args, **kwargs):
+
+ def pytest_sessionstart(self, session):
+
+ def collect(*args, **kwargs):
accept_filename_predicate = test_filter.make_py_file_filter(session.config.option.test_filter)
full_test_names_file_path = session.config.option.test_list_path
filenames_filter = None
@@ -111,7 +111,7 @@ class CollectionPlugin(object):
full_names_filter = set(json.load(afile)[int(session.config.option.modulo_index)])
filenames_filter = set(map(lambda x: x.split('::')[0], full_names_filter))
- for test_module in self._test_modules:
+ for test_module in self._test_modules:
module = LoadedModule.from_parent(name=test_module, parent=session)
if not pytest_ignore_collect(module, session, filenames_filter, accept_filename_predicate):
yield module
@@ -120,9 +120,9 @@ class CollectionPlugin(object):
module = DoctestModule.from_parent(name=test_module, parent=session)
if not pytest_ignore_collect(module, session, filenames_filter, accept_filename_predicate):
yield module
-
+
if os.environ.get('YA_PYTEST_DISABLE_DOCTEST', 'no') == 'no':
for doctest_module in self._doctest_modules:
yield DoctestModule.from_parent(name=doctest_module, parent=session, namespace=False)
- session.collect = collect
+ session.collect = collect
diff --git a/library/python/pytest/plugins/conftests.py b/library/python/pytest/plugins/conftests.py
index dfae771ef8..522041f5a7 100644
--- a/library/python/pytest/plugins/conftests.py
+++ b/library/python/pytest/plugins/conftests.py
@@ -1,26 +1,26 @@
import os
-import importlib
+import importlib
import sys
-import inspect
+import inspect
from pytest import hookimpl
from .fixtures import metrics, links # noqa
-
-orig_getfile = inspect.getfile
-
-
-def getfile(object):
- res = orig_getfile(object)
- if inspect.ismodule(object):
- if not res and getattr(object, '__orig_file__'):
- res = object.__orig_file__
- return res
-
-inspect.getfile = getfile
+
+orig_getfile = inspect.getfile
+
+
+def getfile(object):
+ res = orig_getfile(object)
+ if inspect.ismodule(object):
+ if not res and getattr(object, '__orig_file__'):
+ res = object.__orig_file__
+ return res
+
+inspect.getfile = getfile
conftest_modules = []
-
-
+
+
@hookimpl(trylast=True)
def pytest_load_initial_conftests(early_config, parser, args):
conftests = filter(lambda name: name.endswith(".conftest"), sys.extra_modules)
@@ -45,6 +45,6 @@ def getconftestmodules(*args, **kwargs):
def pytest_sessionstart(session):
- # Override filesystem based relevant conftest discovery on the call path
- assert session.config.pluginmanager
- session.config.pluginmanager._getconftestmodules = getconftestmodules
+ # Override filesystem based relevant conftest discovery on the call path
+ assert session.config.pluginmanager
+ session.config.pluginmanager._getconftestmodules = getconftestmodules
diff --git a/library/python/pytest/plugins/fixtures.py b/library/python/pytest/plugins/fixtures.py
index 9f5fd6ccf1..6f7e0a27e4 100644
--- a/library/python/pytest/plugins/fixtures.py
+++ b/library/python/pytest/plugins/fixtures.py
@@ -1,26 +1,26 @@
-import os
-import pytest
+import os
+import pytest
import six
-
-
-MAX_ALLOWED_LINKS_COUNT = 10
-
-
-@pytest.fixture
-def metrics(request):
-
- class Metrics(object):
- @classmethod
- def set(cls, name, value):
- assert len(name) <= 128, "Length of the metric name must less than 128"
- assert type(value) in [int, float], "Metric value must be of type int or float"
- test_name = request.node.nodeid
- if test_name not in request.config.test_metrics:
- request.config.test_metrics[test_name] = {}
- request.config.test_metrics[test_name][name] = value
-
- @classmethod
- def set_benchmark(cls, benchmark_values):
+
+
+MAX_ALLOWED_LINKS_COUNT = 10
+
+
+@pytest.fixture
+def metrics(request):
+
+ class Metrics(object):
+ @classmethod
+ def set(cls, name, value):
+ assert len(name) <= 128, "Length of the metric name must less than 128"
+ assert type(value) in [int, float], "Metric value must be of type int or float"
+ test_name = request.node.nodeid
+ if test_name not in request.config.test_metrics:
+ request.config.test_metrics[test_name] = {}
+ request.config.test_metrics[test_name][name] = value
+
+ @classmethod
+ def set_benchmark(cls, benchmark_values):
# report of google has key 'benchmarks' which is a list of benchmark results
# yandex benchmark has key 'benchmark', which is a list of benchmark results
# use this to differentiate which kind of result it is
@@ -31,12 +31,12 @@ def metrics(request):
@classmethod
def set_ybenchmark(cls, benchmark_values):
- for benchmark in benchmark_values["benchmark"]:
- name = benchmark["name"]
+ for benchmark in benchmark_values["benchmark"]:
+ name = benchmark["name"]
for key, value in six.iteritems(benchmark):
- if key != "name":
- cls.set("{}_{}".format(name, key), value)
-
+ if key != "name":
+ cls.set("{}_{}".format(name, key), value)
+
@classmethod
def set_gbenchmark(cls, benchmark_values):
time_unit_multipliers = {"ns": 1, "us": 1000, "ms": 1000000}
@@ -50,36 +50,36 @@ def metrics(request):
cls.set("{}_{}".format(name, k), v * time_unit_mult)
elif k not in ignore_keys and isinstance(v, (float, int)):
cls.set("{}_{}".format(name, k), v)
- return Metrics
-
-
-@pytest.fixture
-def links(request):
-
- class Links(object):
- @classmethod
- def set(cls, name, path):
-
- if len(request.config.test_logs[request.node.nodeid]) >= MAX_ALLOWED_LINKS_COUNT:
- raise Exception("Cannot add more than {} links to test".format(MAX_ALLOWED_LINKS_COUNT))
-
- reserved_names = ["log", "logsdir", "stdout", "stderr"]
- if name in reserved_names:
- raise Exception("Attachment name should not belong to the reserved list: {}".format(", ".join(reserved_names)))
- output_dir = request.config.ya.output_dir
-
- if not os.path.exists(path):
- raise Exception("Path to be attached does not exist: {}".format(path))
-
- if os.path.isabs(path) and ".." in os.path.relpath(path, output_dir):
- raise Exception("Test attachment must be inside yatest.common.output_path()")
-
- request.config.test_logs[request.node.nodeid][name] = path
-
- @classmethod
- def get(cls, name):
- if name not in request.config.test_logs[request.node.nodeid]:
- raise KeyError("Attachment with name '{}' does not exist".format(name))
- return request.config.test_logs[request.node.nodeid][name]
-
- return Links
+ return Metrics
+
+
+@pytest.fixture
+def links(request):
+
+ class Links(object):
+ @classmethod
+ def set(cls, name, path):
+
+ if len(request.config.test_logs[request.node.nodeid]) >= MAX_ALLOWED_LINKS_COUNT:
+ raise Exception("Cannot add more than {} links to test".format(MAX_ALLOWED_LINKS_COUNT))
+
+ reserved_names = ["log", "logsdir", "stdout", "stderr"]
+ if name in reserved_names:
+ raise Exception("Attachment name should not belong to the reserved list: {}".format(", ".join(reserved_names)))
+ output_dir = request.config.ya.output_dir
+
+ if not os.path.exists(path):
+ raise Exception("Path to be attached does not exist: {}".format(path))
+
+ if os.path.isabs(path) and ".." in os.path.relpath(path, output_dir):
+ raise Exception("Test attachment must be inside yatest.common.output_path()")
+
+ request.config.test_logs[request.node.nodeid][name] = path
+
+ @classmethod
+ def get(cls, name):
+ if name not in request.config.test_logs[request.node.nodeid]:
+ raise KeyError("Attachment with name '{}' does not exist".format(name))
+ return request.config.test_logs[request.node.nodeid][name]
+
+ return Links
diff --git a/library/python/pytest/plugins/ya.make b/library/python/pytest/plugins/ya.make
index 07914cf4d3..c15d6f759d 100644
--- a/library/python/pytest/plugins/ya.make
+++ b/library/python/pytest/plugins/ya.make
@@ -1,20 +1,20 @@
OWNER(g:yatest)
-
+
PY23_LIBRARY()
-
-PY_SRCS(
- ya.py
- collection.py
- conftests.py
- fixtures.py
-)
-
-PEERDIR(
+
+PY_SRCS(
+ ya.py
+ collection.py
+ conftests.py
+ fixtures.py
+)
+
+PEERDIR(
library/python/filelock
- library/python/find_root
+ library/python/find_root
library/python/testing/filter
-)
-
+)
+
IF (PYTHON2)
PY_SRCS(
fakeid_py2.py
@@ -29,4 +29,4 @@ ELSE()
)
ENDIF()
-END()
+END()
diff --git a/library/python/pytest/plugins/ya.py b/library/python/pytest/plugins/ya.py
index c6b06478d9..1bde03042d 100644
--- a/library/python/pytest/plugins/ya.py
+++ b/library/python/pytest/plugins/ya.py
@@ -3,101 +3,101 @@
import base64
import errno
import re
-import sys
-import os
-import logging
-import fnmatch
-import json
-import time
+import sys
+import os
+import logging
+import fnmatch
+import json
+import time
import traceback
-import collections
+import collections
import signal
import inspect
import warnings
import attr
import faulthandler
-import py
-import pytest
+import py
+import pytest
import six
-import _pytest
+import _pytest
import _pytest._io
import _pytest.mark
import _pytest.outcomes
import _pytest.skipping
-
+
from _pytest.warning_types import PytestUnhandledCoroutineWarning
from yatest_lib import test_splitter
-try:
- import resource
-except ImportError:
- resource = None
-
-try:
- import library.python.pytest.yatest_tools as tools
-except ImportError:
- # fallback for pytest script mode
- import yatest_tools as tools
-
+try:
+ import resource
+except ImportError:
+ resource = None
+
+try:
+ import library.python.pytest.yatest_tools as tools
+except ImportError:
+ # fallback for pytest script mode
+ import yatest_tools as tools
+
try:
from library.python import filelock
except ImportError:
filelock = None
-import yatest_lib.tools
-
-import yatest_lib.external as canon
-
+import yatest_lib.tools
+
+import yatest_lib.external as canon
+
import yatest_lib.ya
from library.python.pytest import context
-console_logger = logging.getLogger("console")
-yatest_logger = logging.getLogger("ya.test")
-
-
-_pytest.main.EXIT_NOTESTSCOLLECTED = 0
+console_logger = logging.getLogger("console")
+yatest_logger = logging.getLogger("ya.test")
+
+
+_pytest.main.EXIT_NOTESTSCOLLECTED = 0
SHUTDOWN_REQUESTED = False
-
+
pytest_config = None
-
-def configure_pdb_on_demand():
- import signal
-
- if hasattr(signal, "SIGUSR1"):
- def on_signal(*args):
+
+def configure_pdb_on_demand():
+ import signal
+
+ if hasattr(signal, "SIGUSR1"):
+ def on_signal(*args):
import ipdb
ipdb.set_trace()
-
- signal.signal(signal.SIGUSR1, on_signal)
-
-
-class CustomImporter(object):
- def __init__(self, roots):
- self._roots = roots
-
- def find_module(self, fullname, package_path=None):
- for path in self._roots:
- full_path = self._get_module_path(path, fullname)
-
- if os.path.exists(full_path) and os.path.isdir(full_path) and not os.path.exists(os.path.join(full_path, "__init__.py")):
- open(os.path.join(full_path, "__init__.py"), "w").close()
-
- return None
-
- def _get_module_path(self, path, fullname):
- return os.path.join(path, *fullname.split('.'))
-
-
-class YaTestLoggingFileHandler(logging.FileHandler):
- pass
-
-
+
+ signal.signal(signal.SIGUSR1, on_signal)
+
+
+class CustomImporter(object):
+ def __init__(self, roots):
+ self._roots = roots
+
+ def find_module(self, fullname, package_path=None):
+ for path in self._roots:
+ full_path = self._get_module_path(path, fullname)
+
+ if os.path.exists(full_path) and os.path.isdir(full_path) and not os.path.exists(os.path.join(full_path, "__init__.py")):
+ open(os.path.join(full_path, "__init__.py"), "w").close()
+
+ return None
+
+ def _get_module_path(self, path, fullname):
+ return os.path.join(path, *fullname.split('.'))
+
+
+class YaTestLoggingFileHandler(logging.FileHandler):
+ pass
+
+
class _TokenFilterFormatter(logging.Formatter):
def __init__(self, fmt):
super(_TokenFilterFormatter, self).__init__(fmt)
@@ -123,141 +123,141 @@ class _TokenFilterFormatter(logging.Formatter):
return self._filter(super(_TokenFilterFormatter, self).format(record))
-def setup_logging(log_path, level=logging.DEBUG, *other_logs):
- logs = [log_path] + list(other_logs)
- root_logger = logging.getLogger()
- for i in range(len(root_logger.handlers) - 1, -1, -1):
- if isinstance(root_logger.handlers[i], YaTestLoggingFileHandler):
+def setup_logging(log_path, level=logging.DEBUG, *other_logs):
+ logs = [log_path] + list(other_logs)
+ root_logger = logging.getLogger()
+ for i in range(len(root_logger.handlers) - 1, -1, -1):
+ if isinstance(root_logger.handlers[i], YaTestLoggingFileHandler):
root_logger.handlers.pop(i).close()
- root_logger.setLevel(level)
- for log_file in logs:
- file_handler = YaTestLoggingFileHandler(log_file)
- log_format = '%(asctime)s - %(levelname)s - %(name)s - %(funcName)s: %(message)s'
+ root_logger.setLevel(level)
+ for log_file in logs:
+ file_handler = YaTestLoggingFileHandler(log_file)
+ log_format = '%(asctime)s - %(levelname)s - %(name)s - %(funcName)s: %(message)s'
file_handler.setFormatter(_TokenFilterFormatter(log_format))
- file_handler.setLevel(level)
- root_logger.addHandler(file_handler)
-
-
-def pytest_addoption(parser):
- parser.addoption("--build-root", action="store", dest="build_root", default="", help="path to the build root")
- parser.addoption("--dep-root", action="append", dest="dep_roots", default=[], help="path to the dep build roots")
- parser.addoption("--source-root", action="store", dest="source_root", default="", help="path to the source root")
- parser.addoption("--data-root", action="store", dest="data_root", default="", help="path to the arcadia_tests_data root")
- parser.addoption("--output-dir", action="store", dest="output_dir", default="", help="path to the test output dir")
- parser.addoption("--python-path", action="store", dest="python_path", default="", help="path the canonical python binary")
- parser.addoption("--valgrind-path", action="store", dest="valgrind_path", default="", help="path the canonical valgring binary")
- parser.addoption("--test-filter", action="append", dest="test_filter", default=None, help="test filter")
+ file_handler.setLevel(level)
+ root_logger.addHandler(file_handler)
+
+
+def pytest_addoption(parser):
+ parser.addoption("--build-root", action="store", dest="build_root", default="", help="path to the build root")
+ parser.addoption("--dep-root", action="append", dest="dep_roots", default=[], help="path to the dep build roots")
+ parser.addoption("--source-root", action="store", dest="source_root", default="", help="path to the source root")
+ parser.addoption("--data-root", action="store", dest="data_root", default="", help="path to the arcadia_tests_data root")
+ parser.addoption("--output-dir", action="store", dest="output_dir", default="", help="path to the test output dir")
+ parser.addoption("--python-path", action="store", dest="python_path", default="", help="path the canonical python binary")
+ parser.addoption("--valgrind-path", action="store", dest="valgrind_path", default="", help="path the canonical valgring binary")
+ parser.addoption("--test-filter", action="append", dest="test_filter", default=None, help="test filter")
parser.addoption("--test-file-filter", action="store", dest="test_file_filter", default=None, help="test file filter")
- parser.addoption("--test-param", action="append", dest="test_params", default=None, help="test parameters")
- parser.addoption("--test-log-level", action="store", dest="test_log_level", choices=["critical", "error", "warning", "info", "debug"], default="debug", help="test log level")
+ parser.addoption("--test-param", action="append", dest="test_params", default=None, help="test parameters")
+ parser.addoption("--test-log-level", action="store", dest="test_log_level", choices=["critical", "error", "warning", "info", "debug"], default="debug", help="test log level")
parser.addoption("--mode", action="store", choices=[yatest_lib.ya.RunMode.List, yatest_lib.ya.RunMode.Run], dest="mode", default=yatest_lib.ya.RunMode.Run, help="testing mode")
parser.addoption("--test-list-file", action="store", dest="test_list_file")
- parser.addoption("--modulo", default=1, type=int)
- parser.addoption("--modulo-index", default=0, type=int)
+ parser.addoption("--modulo", default=1, type=int)
+ parser.addoption("--modulo-index", default=0, type=int)
parser.addoption("--partition-mode", default='SEQUENTIAL', help="Split tests according to partitoin mode")
- parser.addoption("--split-by-tests", action='store_true', help="Split test execution by tests instead of suites", default=False)
- parser.addoption("--project-path", action="store", default="", help="path to CMakeList where test is declared")
- parser.addoption("--build-type", action="store", default="", help="build type")
+ parser.addoption("--split-by-tests", action='store_true', help="Split test execution by tests instead of suites", default=False)
+ parser.addoption("--project-path", action="store", default="", help="path to CMakeList where test is declared")
+ parser.addoption("--build-type", action="store", default="", help="build type")
parser.addoption("--flags", action="append", dest="flags", default=[], help="build flags (-D)")
parser.addoption("--sanitize", action="store", default="", help="sanitize mode")
- parser.addoption("--test-stderr", action="store_true", default=False, help="test stderr")
+ parser.addoption("--test-stderr", action="store_true", default=False, help="test stderr")
parser.addoption("--test-debug", action="store_true", default=False, help="test debug mode")
- parser.addoption("--root-dir", action="store", default=None)
- parser.addoption("--ya-trace", action="store", dest="ya_trace_path", default=None, help="path to ya trace report")
+ parser.addoption("--root-dir", action="store", default=None)
+ parser.addoption("--ya-trace", action="store", dest="ya_trace_path", default=None, help="path to ya trace report")
parser.addoption("--ya-version", action="store", dest="ya_version", default=0, type=int, help="allows to be compatible with ya and the new changes in ya-dev")
- parser.addoption(
- "--test-suffix", action="store", dest="test_suffix", default=None, help="add suffix to every test name"
- )
- parser.addoption("--gdb-path", action="store", dest="gdb_path", default="", help="path the canonical gdb binary")
- parser.addoption("--collect-cores", action="store_true", dest="collect_cores", default=False, help="allows core dump file recovering during test")
+ parser.addoption(
+ "--test-suffix", action="store", dest="test_suffix", default=None, help="add suffix to every test name"
+ )
+ parser.addoption("--gdb-path", action="store", dest="gdb_path", default="", help="path the canonical gdb binary")
+ parser.addoption("--collect-cores", action="store_true", dest="collect_cores", default=False, help="allows core dump file recovering during test")
parser.addoption("--sanitizer-extra-checks", action="store_true", dest="sanitizer_extra_checks", default=False, help="enables extra checks for tests built with sanitizers")
- parser.addoption("--report-deselected", action="store_true", dest="report_deselected", default=False, help="report deselected tests to the trace file")
- parser.addoption("--pdb-on-sigusr1", action="store_true", default=False, help="setup pdb.set_trace on SIGUSR1")
+ parser.addoption("--report-deselected", action="store_true", dest="report_deselected", default=False, help="report deselected tests to the trace file")
+ parser.addoption("--pdb-on-sigusr1", action="store_true", default=False, help="setup pdb.set_trace on SIGUSR1")
parser.addoption("--test-tool-bin", help="Path to test_tool")
parser.addoption("--test-list-path", dest="test_list_path", action="store", help="path to test list", default="")
-
-
+
+
def from_ya_test():
return "YA_TEST_RUNNER" in os.environ
-def pytest_configure(config):
+def pytest_configure(config):
global pytest_config
pytest_config = config
config.option.continue_on_collection_errors = True
-
+
config.addinivalue_line("markers", "ya:external")
config.from_ya_test = from_ya_test()
- config.test_logs = collections.defaultdict(dict)
- config.test_metrics = {}
+ config.test_logs = collections.defaultdict(dict)
+ config.test_metrics = {}
config.suite_metrics = {}
config.configure_timestamp = time.time()
- context = {
- "project_path": config.option.project_path,
- "test_stderr": config.option.test_stderr,
+ context = {
+ "project_path": config.option.project_path,
+ "test_stderr": config.option.test_stderr,
"test_debug": config.option.test_debug,
- "build_type": config.option.build_type,
- "test_traceback": config.option.tbstyle,
+ "build_type": config.option.build_type,
+ "test_traceback": config.option.tbstyle,
"flags": config.option.flags,
"sanitize": config.option.sanitize,
- }
+ }
if config.option.collectonly:
config.option.mode = yatest_lib.ya.RunMode.List
config.ya = yatest_lib.ya.Ya(
- config.option.mode,
- config.option.source_root,
- config.option.build_root,
- config.option.dep_roots,
- config.option.output_dir,
- config.option.test_params,
- context,
- config.option.python_path,
- config.option.valgrind_path,
- config.option.gdb_path,
- config.option.data_root,
- )
- config.option.test_log_level = {
- "critical": logging.CRITICAL,
- "error": logging.ERROR,
- "warning": logging.WARN,
- "info": logging.INFO,
- "debug": logging.DEBUG,
- }[config.option.test_log_level]
-
- if not config.option.collectonly:
- setup_logging(os.path.join(config.ya.output_dir, "run.log"), config.option.test_log_level)
- config.current_item_nodeid = None
- config.current_test_name = None
- config.test_cores_count = 0
- config.collect_cores = config.option.collect_cores
+ config.option.mode,
+ config.option.source_root,
+ config.option.build_root,
+ config.option.dep_roots,
+ config.option.output_dir,
+ config.option.test_params,
+ context,
+ config.option.python_path,
+ config.option.valgrind_path,
+ config.option.gdb_path,
+ config.option.data_root,
+ )
+ config.option.test_log_level = {
+ "critical": logging.CRITICAL,
+ "error": logging.ERROR,
+ "warning": logging.WARN,
+ "info": logging.INFO,
+ "debug": logging.DEBUG,
+ }[config.option.test_log_level]
+
+ if not config.option.collectonly:
+ setup_logging(os.path.join(config.ya.output_dir, "run.log"), config.option.test_log_level)
+ config.current_item_nodeid = None
+ config.current_test_name = None
+ config.test_cores_count = 0
+ config.collect_cores = config.option.collect_cores
config.sanitizer_extra_checks = config.option.sanitizer_extra_checks
try:
config.test_tool_bin = config.option.test_tool_bin
except AttributeError:
logging.info("test_tool_bin not specified")
-
- if config.sanitizer_extra_checks:
+
+ if config.sanitizer_extra_checks:
for envvar in ['LSAN_OPTIONS', 'ASAN_OPTIONS']:
if envvar in os.environ:
os.environ.pop(envvar)
if envvar + '_ORIGINAL' in os.environ:
os.environ[envvar] = os.environ[envvar + '_ORIGINAL']
- if config.option.root_dir:
+ if config.option.root_dir:
config.rootdir = py.path.local(config.option.root_dir)
config.invocation_params = attr.evolve(config.invocation_params, dir=config.rootdir)
-
+
extra_sys_path = []
# Arcadia paths from the test DEPENDS section of ya.make
extra_sys_path.append(os.path.join(config.option.source_root, config.option.project_path))
- # Build root is required for correct import of protobufs, because imports are related to the root
- # (like import devtools.dummy_arcadia.protos.lib.my_proto_pb2)
+ # Build root is required for correct import of protobufs, because imports are related to the root
+ # (like import devtools.dummy_arcadia.protos.lib.my_proto_pb2)
extra_sys_path.append(config.option.build_root)
-
+
for path in config.option.dep_roots:
if os.path.isabs(path):
extra_sys_path.append(path)
@@ -272,17 +272,17 @@ def pytest_configure(config):
os.environ["PYTHONPATH"] = os.pathsep.join(sys.path)
- if not config.option.collectonly:
- if config.option.ya_trace_path:
- config.ya_trace_reporter = TraceReportGenerator(config.option.ya_trace_path)
- else:
- config.ya_trace_reporter = DryTraceReportGenerator(config.option.ya_trace_path)
+ if not config.option.collectonly:
+ if config.option.ya_trace_path:
+ config.ya_trace_reporter = TraceReportGenerator(config.option.ya_trace_path)
+ else:
+ config.ya_trace_reporter = DryTraceReportGenerator(config.option.ya_trace_path)
config.ya_version = config.option.ya_version
-
- sys.meta_path.append(CustomImporter([config.option.build_root] + [os.path.join(config.option.build_root, dep) for dep in config.option.dep_roots]))
- if config.option.pdb_on_sigusr1:
- configure_pdb_on_demand()
-
+
+ sys.meta_path.append(CustomImporter([config.option.build_root] + [os.path.join(config.option.build_root, dep) for dep in config.option.dep_roots]))
+ if config.option.pdb_on_sigusr1:
+ configure_pdb_on_demand()
+
# Dump python backtrace in case of any errors
faulthandler.enable()
if hasattr(signal, "SIGQUIT"):
@@ -291,7 +291,7 @@ def pytest_configure(config):
if hasattr(signal, "SIGUSR2"):
signal.signal(signal.SIGUSR2, _graceful_shutdown)
-
+
session_should_exit = False
@@ -327,122 +327,122 @@ def _graceful_shutdown(*args):
_graceful_shutdown_on_log(not capman.is_globally_capturing())
-def _get_rusage():
- return resource and resource.getrusage(resource.RUSAGE_SELF)
-
-
-def _collect_test_rusage(item):
- if resource and hasattr(item, "rusage"):
- finish_rusage = _get_rusage()
+def _get_rusage():
+ return resource and resource.getrusage(resource.RUSAGE_SELF)
+
+
+def _collect_test_rusage(item):
+ if resource and hasattr(item, "rusage"):
+ finish_rusage = _get_rusage()
ya_inst = pytest_config.ya
-
- def add_metric(attr_name, metric_name=None, modifier=None):
- if not metric_name:
- metric_name = attr_name
- if not modifier:
- modifier = lambda x: x
- if hasattr(item.rusage, attr_name):
+
+ def add_metric(attr_name, metric_name=None, modifier=None):
+ if not metric_name:
+ metric_name = attr_name
+ if not modifier:
+ modifier = lambda x: x
+ if hasattr(item.rusage, attr_name):
ya_inst.set_metric_value(metric_name, modifier(getattr(finish_rusage, attr_name) - getattr(item.rusage, attr_name)))
-
- for args in [
- ("ru_maxrss", "ru_rss", lambda x: x*1024), # to be the same as in util/system/rusage.cpp
- ("ru_utime",),
- ("ru_stime",),
- ("ru_ixrss", None, lambda x: x*1024),
- ("ru_idrss", None, lambda x: x*1024),
- ("ru_isrss", None, lambda x: x*1024),
- ("ru_majflt", "ru_major_pagefaults"),
- ("ru_minflt", "ru_minor_pagefaults"),
- ("ru_nswap",),
- ("ru_inblock",),
- ("ru_oublock",),
- ("ru_msgsnd",),
- ("ru_msgrcv",),
- ("ru_nsignals",),
- ("ru_nvcsw",),
- ("ru_nivcsw",),
- ]:
- add_metric(*args)
-
-
-def _get_item_tags(item):
- tags = []
- for key, value in item.keywords.items():
+
+ for args in [
+ ("ru_maxrss", "ru_rss", lambda x: x*1024), # to be the same as in util/system/rusage.cpp
+ ("ru_utime",),
+ ("ru_stime",),
+ ("ru_ixrss", None, lambda x: x*1024),
+ ("ru_idrss", None, lambda x: x*1024),
+ ("ru_isrss", None, lambda x: x*1024),
+ ("ru_majflt", "ru_major_pagefaults"),
+ ("ru_minflt", "ru_minor_pagefaults"),
+ ("ru_nswap",),
+ ("ru_inblock",),
+ ("ru_oublock",),
+ ("ru_msgsnd",),
+ ("ru_msgrcv",),
+ ("ru_nsignals",),
+ ("ru_nvcsw",),
+ ("ru_nivcsw",),
+ ]:
+ add_metric(*args)
+
+
+def _get_item_tags(item):
+ tags = []
+ for key, value in item.keywords.items():
if key == 'pytestmark' and isinstance(value, list):
for mark in value:
tags.append(mark.name)
elif isinstance(value, _pytest.mark.MarkDecorator):
- tags.append(key)
- return tags
-
-
-def pytest_runtest_setup(item):
- item.rusage = _get_rusage()
+ tags.append(key)
+ return tags
+
+
+def pytest_runtest_setup(item):
+ item.rusage = _get_rusage()
pytest_config.test_cores_count = 0
pytest_config.current_item_nodeid = item.nodeid
- class_name, test_name = tools.split_node_id(item.nodeid)
+ class_name, test_name = tools.split_node_id(item.nodeid)
test_log_path = tools.get_test_log_file_path(pytest_config.ya.output_dir, class_name, test_name)
- setup_logging(
+ setup_logging(
os.path.join(pytest_config.ya.output_dir, "run.log"),
pytest_config.option.test_log_level,
- test_log_path
- )
+ test_log_path
+ )
pytest_config.test_logs[item.nodeid]['log'] = test_log_path
pytest_config.test_logs[item.nodeid]['logsdir'] = pytest_config.ya.output_dir
pytest_config.current_test_log_path = test_log_path
pytest_config.current_test_name = "{}::{}".format(class_name, test_name)
- separator = "#" * 100
- yatest_logger.info(separator)
- yatest_logger.info(test_name)
- yatest_logger.info(separator)
- yatest_logger.info("Test setup")
-
+ separator = "#" * 100
+ yatest_logger.info(separator)
+ yatest_logger.info(test_name)
+ yatest_logger.info(separator)
+ yatest_logger.info("Test setup")
+
test_item = CrashedTestItem(item.nodeid, pytest_config.option.test_suffix)
pytest_config.ya_trace_reporter.on_start_test_class(test_item)
pytest_config.ya_trace_reporter.on_start_test_case(test_item)
-
-
-def pytest_runtest_teardown(item, nextitem):
- yatest_logger.info("Test teardown")
-
-
-def pytest_runtest_call(item):
+
+
+def pytest_runtest_teardown(item, nextitem):
+ yatest_logger.info("Test teardown")
+
+
+def pytest_runtest_call(item):
class_name, test_name = tools.split_node_id(item.nodeid)
yatest_logger.info("Test call (class_name: %s, test_name: %s)", class_name, test_name)
-
-
-def pytest_deselected(items):
+
+
+def pytest_deselected(items):
config = pytest_config
- if config.option.report_deselected:
- for item in items:
- deselected_item = DeselectedTestItem(item.nodeid, config.option.test_suffix)
- config.ya_trace_reporter.on_start_test_class(deselected_item)
- config.ya_trace_reporter.on_finish_test_case(deselected_item)
- config.ya_trace_reporter.on_finish_test_class(deselected_item)
-
-
-@pytest.mark.trylast
-def pytest_collection_modifyitems(items, config):
-
- def filter_items(filters):
- filtered_items = []
- deselected_items = []
- for item in items:
+ if config.option.report_deselected:
+ for item in items:
+ deselected_item = DeselectedTestItem(item.nodeid, config.option.test_suffix)
+ config.ya_trace_reporter.on_start_test_class(deselected_item)
+ config.ya_trace_reporter.on_finish_test_case(deselected_item)
+ config.ya_trace_reporter.on_finish_test_class(deselected_item)
+
+
+@pytest.mark.trylast
+def pytest_collection_modifyitems(items, config):
+
+ def filter_items(filters):
+ filtered_items = []
+ deselected_items = []
+ for item in items:
canonical_node_id = str(CustomTestItem(item.nodeid, pytest_config.option.test_suffix))
- matched = False
- for flt in filters:
+ matched = False
+ for flt in filters:
if "::" not in flt and "*" not in flt:
- flt += "*" # add support for filtering by module name
- if canonical_node_id.endswith(flt) or fnmatch.fnmatch(tools.escape_for_fnmatch(canonical_node_id), tools.escape_for_fnmatch(flt)):
- matched = True
- if matched:
- filtered_items.append(item)
- else:
- deselected_items.append(item)
-
- config.hook.pytest_deselected(items=deselected_items)
- items[:] = filtered_items
-
+ flt += "*" # add support for filtering by module name
+ if canonical_node_id.endswith(flt) or fnmatch.fnmatch(tools.escape_for_fnmatch(canonical_node_id), tools.escape_for_fnmatch(flt)):
+ matched = True
+ if matched:
+ filtered_items.append(item)
+ else:
+ deselected_items.append(item)
+
+ config.hook.pytest_deselected(items=deselected_items)
+ items[:] = filtered_items
+
def filter_by_full_name(filters):
filter_set = {flt for flt in filters}
filtered_items = []
@@ -456,10 +456,10 @@ def pytest_collection_modifyitems(items, config):
config.hook.pytest_deselected(items=deselected_items)
items[:] = filtered_items
- # XXX - check to be removed when tests for peerdirs don't run
- for item in items:
- if not item.nodeid:
- item._nodeid = os.path.basename(item.location[0])
+ # XXX - check to be removed when tests for peerdirs don't run
+ for item in items:
+ if not item.nodeid:
+ item._nodeid = os.path.basename(item.location[0])
if os.path.exists(config.option.test_list_path):
with open(config.option.test_list_path, 'r') as afile:
chunks = json.load(afile)
@@ -490,39 +490,39 @@ def pytest_collection_modifyitems(items, config):
for item in chunk_items:
items.extend(item)
yatest_logger.info("Modulo %s tests are: %s", modulo_index, chunk_items)
-
+
if config.option.mode == yatest_lib.ya.RunMode.Run:
- for item in items:
- test_item = NotLaunchedTestItem(item.nodeid, config.option.test_suffix)
- config.ya_trace_reporter.on_start_test_class(test_item)
- config.ya_trace_reporter.on_finish_test_case(test_item)
- config.ya_trace_reporter.on_finish_test_class(test_item)
+ for item in items:
+ test_item = NotLaunchedTestItem(item.nodeid, config.option.test_suffix)
+ config.ya_trace_reporter.on_start_test_class(test_item)
+ config.ya_trace_reporter.on_finish_test_case(test_item)
+ config.ya_trace_reporter.on_finish_test_class(test_item)
elif config.option.mode == yatest_lib.ya.RunMode.List:
- tests = []
- for item in items:
+ tests = []
+ for item in items:
item = CustomTestItem(item.nodeid, pytest_config.option.test_suffix, item.keywords)
- record = {
- "class": item.class_name,
- "test": item.test_name,
- "tags": _get_item_tags(item),
- }
- tests.append(record)
+ record = {
+ "class": item.class_name,
+ "test": item.test_name,
+ "tags": _get_item_tags(item),
+ }
+ tests.append(record)
if config.option.test_list_file:
with open(config.option.test_list_file, 'w') as afile:
json.dump(tests, afile)
# TODO prettyboy remove after test_tool release - currently it's required for backward compatibility
- sys.stderr.write(json.dumps(tests))
-
-
-def pytest_collectreport(report):
- if not report.passed:
+ sys.stderr.write(json.dumps(tests))
+
+
+def pytest_collectreport(report):
+ if not report.passed:
if hasattr(pytest_config, 'ya_trace_reporter'):
test_item = TestItem(report, None, pytest_config.option.test_suffix)
pytest_config.ya_trace_reporter.on_error(test_item)
- else:
- sys.stderr.write(yatest_lib.tools.to_utf8(report.longrepr))
-
-
+ else:
+ sys.stderr.write(yatest_lib.tools.to_utf8(report.longrepr))
+
+
@pytest.mark.tryfirst
def pytest_pyfunc_call(pyfuncitem):
testfunction = pyfuncitem.obj
@@ -542,7 +542,7 @@ def pytest_pyfunc_call(pyfuncitem):
@pytest.hookimpl(hookwrapper=True)
-def pytest_runtest_makereport(item, call):
+def pytest_runtest_makereport(item, call):
def logreport(report, result, call):
test_item = TestItem(report, result, pytest_config.option.test_suffix)
if not pytest_config.suite_metrics and context.Ctx.get("YA_PYTEST_START_TIMESTAMP"):
@@ -554,24 +554,24 @@ def pytest_runtest_makereport(item, call):
if report.outcome == "failed":
yatest_logger.error(report.longrepr)
- if report.when == "call":
- _collect_test_rusage(item)
+ if report.when == "call":
+ _collect_test_rusage(item)
pytest_config.ya_trace_reporter.on_finish_test_case(test_item)
- elif report.when == "setup":
+ elif report.when == "setup":
pytest_config.ya_trace_reporter.on_start_test_class(test_item)
- if report.outcome != "passed":
+ if report.outcome != "passed":
pytest_config.ya_trace_reporter.on_start_test_case(test_item)
pytest_config.ya_trace_reporter.on_finish_test_case(test_item)
- else:
+ else:
pytest_config.ya_trace_reporter.on_start_test_case(test_item)
- elif report.when == "teardown":
- if report.outcome == "failed":
+ elif report.when == "teardown":
+ if report.outcome == "failed":
pytest_config.ya_trace_reporter.on_start_test_case(test_item)
pytest_config.ya_trace_reporter.on_finish_test_case(test_item)
else:
pytest_config.ya_trace_reporter.on_finish_test_case(test_item, duration_only=True)
pytest_config.ya_trace_reporter.on_finish_test_class(test_item)
-
+
outcome = yield
rep = outcome.get_result()
result = None
@@ -580,10 +580,10 @@ def pytest_runtest_makereport(item, call):
if not pytest_config.from_ya_test:
ti = TestItem(rep, result, pytest_config.option.test_suffix)
tr = pytest_config.pluginmanager.getplugin('terminalreporter')
- tr.write_line("{} - Validating canonical data is not supported when running standalone binary".format(ti), yellow=True, bold=True)
+ tr.write_line("{} - Validating canonical data is not supported when running standalone binary".format(ti), yellow=True, bold=True)
logreport(rep, result, call)
-
-
+
+
def pytest_make_parametrize_id(config, val, argname):
# Avoid <, > symbols in canondata file names
if inspect.isfunction(val) and val.__name__ == "<lambda>":
@@ -598,7 +598,7 @@ def get_formatted_error(report):
text += colorize(entry)
else:
text = colorize(report.longrepr)
- text = yatest_lib.tools.to_utf8(text)
+ text = yatest_lib.tools.to_utf8(text)
return text
@@ -616,9 +616,9 @@ def colorize(longrepr):
if hasattr(longrepr, 'reprtraceback') and hasattr(longrepr.reprtraceback, 'toterminal'):
longrepr.reprtraceback.toterminal(writer)
return io.getvalue().strip()
- return yatest_lib.tools.to_utf8(longrepr)
+ return yatest_lib.tools.to_utf8(longrepr)
- text = yatest_lib.tools.to_utf8(longrepr)
+ text = yatest_lib.tools.to_utf8(longrepr)
pos = text.find("E ")
if pos == -1:
return text
@@ -633,25 +633,25 @@ def colorize(longrepr):
return "{}[[bad]]{}".format(bt, error)
-class TestItem(object):
-
- def __init__(self, report, result, test_suffix):
- self._result = result
- self.nodeid = report.nodeid
- self._class_name, self._test_name = tools.split_node_id(self.nodeid, test_suffix)
- self._error = None
- self._status = None
- self._process_report(report)
- self._duration = hasattr(report, 'duration') and report.duration or 0
- self._keywords = getattr(report, "keywords", {})
-
- def _process_report(self, report):
- if report.longrepr:
- self.set_error(report)
- if hasattr(report, 'when') and report.when != "call":
- self.set_error(report.when + " failed:\n" + self._error)
- else:
- self.set_error("")
+class TestItem(object):
+
+ def __init__(self, report, result, test_suffix):
+ self._result = result
+ self.nodeid = report.nodeid
+ self._class_name, self._test_name = tools.split_node_id(self.nodeid, test_suffix)
+ self._error = None
+ self._status = None
+ self._process_report(report)
+ self._duration = hasattr(report, 'duration') and report.duration or 0
+ self._keywords = getattr(report, "keywords", {})
+
+ def _process_report(self, report):
+ if report.longrepr:
+ self.set_error(report)
+ if hasattr(report, 'when') and report.when != "call":
+ self.set_error(report.when + " failed:\n" + self._error)
+ else:
+ self.set_error("")
report_teststatus = _pytest.skipping.pytest_report_teststatus(report)
if report_teststatus is not None:
@@ -667,89 +667,89 @@ class TestItem(object):
self._status = 'skipped'
self.set_error(yatest_lib.tools.to_utf8(report.longrepr[-1]))
elif report.passed:
- self._status = 'good'
- self.set_error("")
+ self._status = 'good'
+ self.set_error("")
else:
self._status = 'fail'
-
- @property
- def status(self):
- return self._status
-
- def set_status(self, status):
- self._status = status
-
- @property
- def test_name(self):
- return tools.normalize_name(self._test_name)
-
- @property
- def class_name(self):
- return tools.normalize_name(self._class_name)
-
- @property
- def error(self):
- return self._error
-
+
+ @property
+ def status(self):
+ return self._status
+
+ def set_status(self, status):
+ self._status = status
+
+ @property
+ def test_name(self):
+ return tools.normalize_name(self._test_name)
+
+ @property
+ def class_name(self):
+ return tools.normalize_name(self._class_name)
+
+ @property
+ def error(self):
+ return self._error
+
def set_error(self, entry, marker='bad'):
if isinstance(entry, _pytest.reports.BaseReport):
- self._error = get_formatted_error(entry)
- else:
+ self._error = get_formatted_error(entry)
+ else:
self._error = "[[{}]]{}".format(yatest_lib.tools.to_str(marker), yatest_lib.tools.to_str(entry))
-
- @property
- def duration(self):
- return self._duration
-
- @property
- def result(self):
- if 'not_canonize' in self._keywords:
- return None
- return self._result
-
- @property
- def keywords(self):
- return self._keywords
-
- def __str__(self):
- return "{}::{}".format(self.class_name, self.test_name)
-
-
-class CustomTestItem(TestItem):
-
- def __init__(self, nodeid, test_suffix, keywords=None):
- self._result = None
- self.nodeid = nodeid
- self._class_name, self._test_name = tools.split_node_id(nodeid, test_suffix)
- self._duration = 0
- self._error = ""
- self._keywords = keywords if keywords is not None else {}
-
-
-class NotLaunchedTestItem(CustomTestItem):
-
- def __init__(self, nodeid, test_suffix):
- super(NotLaunchedTestItem, self).__init__(nodeid, test_suffix)
- self._status = "not_launched"
-
-
-class CrashedTestItem(CustomTestItem):
-
- def __init__(self, nodeid, test_suffix):
- super(CrashedTestItem, self).__init__(nodeid, test_suffix)
- self._status = "crashed"
-
-
-class DeselectedTestItem(CustomTestItem):
-
- def __init__(self, nodeid, test_suffix):
- super(DeselectedTestItem, self).__init__(nodeid, test_suffix)
- self._status = "deselected"
-
-
-class TraceReportGenerator(object):
-
- def __init__(self, out_file_path):
+
+ @property
+ def duration(self):
+ return self._duration
+
+ @property
+ def result(self):
+ if 'not_canonize' in self._keywords:
+ return None
+ return self._result
+
+ @property
+ def keywords(self):
+ return self._keywords
+
+ def __str__(self):
+ return "{}::{}".format(self.class_name, self.test_name)
+
+
+class CustomTestItem(TestItem):
+
+ def __init__(self, nodeid, test_suffix, keywords=None):
+ self._result = None
+ self.nodeid = nodeid
+ self._class_name, self._test_name = tools.split_node_id(nodeid, test_suffix)
+ self._duration = 0
+ self._error = ""
+ self._keywords = keywords if keywords is not None else {}
+
+
+class NotLaunchedTestItem(CustomTestItem):
+
+ def __init__(self, nodeid, test_suffix):
+ super(NotLaunchedTestItem, self).__init__(nodeid, test_suffix)
+ self._status = "not_launched"
+
+
+class CrashedTestItem(CustomTestItem):
+
+ def __init__(self, nodeid, test_suffix):
+ super(CrashedTestItem, self).__init__(nodeid, test_suffix)
+ self._status = "crashed"
+
+
+class DeselectedTestItem(CustomTestItem):
+
+ def __init__(self, nodeid, test_suffix):
+ super(DeselectedTestItem, self).__init__(nodeid, test_suffix)
+ self._status = "deselected"
+
+
+class TraceReportGenerator(object):
+
+ def __init__(self, out_file_path):
self._filename = out_file_path
self._file = open(out_file_path, 'w')
self._wreckage_filename = out_file_path + '.wreckage'
@@ -759,7 +759,7 @@ class TraceReportGenerator(object):
self._current_test = (None, None)
self._pid = os.getpid()
self._check_intricate_respawn()
-
+
def _check_intricate_respawn(self):
pid_file = self._filename + '.pid'
try:
@@ -803,40 +803,40 @@ class TraceReportGenerator(object):
# Test binary is launched without `ya make -t`'s testing machinery - don't rely on clean environment
pass
- def on_start_test_class(self, test_item):
+ def on_start_test_class(self, test_item):
pytest_config.ya.set_test_item_node_id(test_item.nodeid)
class_name = test_item.class_name.decode('utf-8') if sys.version_info[0] < 3 else test_item.class_name
self._current_test = (class_name, None)
self.trace('test-started', {'class': class_name})
-
- def on_finish_test_class(self, test_item):
+
+ def on_finish_test_class(self, test_item):
pytest_config.ya.set_test_item_node_id(test_item.nodeid)
self.trace('test-finished', {'class': test_item.class_name.decode('utf-8') if sys.version_info[0] < 3 else test_item.class_name})
-
- def on_start_test_case(self, test_item):
+
+ def on_start_test_case(self, test_item):
class_name = yatest_lib.tools.to_utf8(test_item.class_name)
subtest_name = yatest_lib.tools.to_utf8(test_item.test_name)
- message = {
+ message = {
'class': class_name,
'subtest': subtest_name,
- }
+ }
if test_item.nodeid in pytest_config.test_logs:
message['logs'] = pytest_config.test_logs[test_item.nodeid]
pytest_config.ya.set_test_item_node_id(test_item.nodeid)
self._current_test = (class_name, subtest_name)
- self.trace('subtest-started', message)
-
+ self.trace('subtest-started', message)
+
def on_finish_test_case(self, test_item, duration_only=False):
if test_item.result is not None:
- try:
+ try:
result = canon.serialize(test_item.result)
- except Exception as e:
- yatest_logger.exception("Error while serializing test results")
- test_item.set_error("Invalid test result: {}".format(e))
- test_item.set_status("fail")
- result = None
- else:
- result = None
+ except Exception as e:
+ yatest_logger.exception("Error while serializing test results")
+ test_item.set_error("Invalid test result: {}".format(e))
+ test_item.set_status("fail")
+ result = None
+ else:
+ result = None
if duration_only and test_item.nodeid in self._test_messages: # add teardown time
message = self._test_messages[test_item.nodeid]
@@ -860,7 +860,7 @@ class TraceReportGenerator(object):
self.trace('subtest-finished', message)
self._test_messages[test_item.nodeid] = message
-
+
def dump_suite_metrics(self):
message = {"metrics": pytest_config.suite_metrics}
self.trace("suite-event", message)
@@ -874,28 +874,28 @@ class TraceReportGenerator(object):
else:
self._test_duration[test_item.nodeid] = test_item._duration
- @staticmethod
- def _get_comment(test_item):
- msg = yatest_lib.tools.to_utf8(test_item.error)
- if not msg:
- return ""
+ @staticmethod
+ def _get_comment(test_item):
+ msg = yatest_lib.tools.to_utf8(test_item.error)
+ if not msg:
+ return ""
return msg + "[[rst]]"
-
+
def _dump_trace(self, name, value):
- event = {
- 'timestamp': time.time(),
- 'value': value,
- 'name': name
- }
+ event = {
+ 'timestamp': time.time(),
+ 'value': value,
+ 'name': name
+ }
data = yatest_lib.tools.to_str(json.dumps(event, ensure_ascii=False))
self._file.write(data + '\n')
self._file.flush()
-
+
def _check_sloppy_fork(self, name, value):
if self._pid == os.getpid():
return
-
+
yatest_logger.error("Skip tracing to avoid data corruption, name = %s, value = %s", name, value)
try:
@@ -950,14 +950,14 @@ class TraceReportGenerator(object):
self._dump_trace(name, value)
-class DryTraceReportGenerator(TraceReportGenerator):
- """
- Generator does not write any information.
- """
-
- def __init__(self, *args, **kwargs):
+class DryTraceReportGenerator(TraceReportGenerator):
+ """
+ Generator does not write any information.
+ """
+
+ def __init__(self, *args, **kwargs):
self._test_messages = {}
self._test_duration = {}
-
- def trace(self, name, value):
- pass
+
+ def trace(self, name, value):
+ pass
diff --git a/library/python/pytest/pytest.yatest.ini b/library/python/pytest/pytest.yatest.ini
index 554a1eb84f..70d6c98516 100644
--- a/library/python/pytest/pytest.yatest.ini
+++ b/library/python/pytest/pytest.yatest.ini
@@ -1,7 +1,7 @@
-[pytest]
+[pytest]
pep8maxlinelength = 200
norecursedirs = *
-pep8ignore = E127 E123 E226 E24
+pep8ignore = E127 E123 E226 E24
filterwarnings =
ignore::pytest.RemovedInPytest4Warning
addopts = -p no:warnings
diff --git a/library/python/pytest/ya.make b/library/python/pytest/ya.make
index ee3c47dccb..060c92c313 100644
--- a/library/python/pytest/ya.make
+++ b/library/python/pytest/ya.make
@@ -1,32 +1,32 @@
PY23_LIBRARY()
-
+
OWNER(
g:yatool
dmitko
)
-
-PY_SRCS(
+
+PY_SRCS(
__init__.py
- main.py
+ main.py
rewrite.py
- yatest_tools.py
+ yatest_tools.py
context.py
-)
-
-PEERDIR(
+)
+
+PEERDIR(
contrib/python/dateutil
contrib/python/ipdb
contrib/python/py
contrib/python/pytest
contrib/python/requests
- library/python/pytest/plugins
- library/python/testing/yatest_common
- library/python/testing/yatest_lib
-)
-
+ library/python/pytest/plugins
+ library/python/testing/yatest_common
+ library/python/testing/yatest_lib
+)
+
RESOURCE_FILES(
PREFIX library/python/pytest/
pytest.yatest.ini
)
-END()
+END()
diff --git a/library/python/pytest/yatest_tools.py b/library/python/pytest/yatest_tools.py
index c618f8ff07..6b8b896394 100644
--- a/library/python/pytest/yatest_tools.py
+++ b/library/python/pytest/yatest_tools.py
@@ -3,13 +3,13 @@
import collections
import functools
import math
-import os
-import re
+import os
+import re
import sys
-
-import yatest_lib.tools
-
-
+
+import yatest_lib.tools
+
+
class Subtest(object):
def __init__(self, name, test_name, status, comment, elapsed, result=None, test_type=None, logs=None, cwd=None, metrics=None):
self._name = name
@@ -17,103 +17,103 @@ class Subtest(object):
self.status = status
self.elapsed = elapsed
self.comment = comment
- self.result = result
- self.test_type = test_type
+ self.result = result
+ self.test_type = test_type
self.logs = logs or {}
- self.cwd = cwd
- self.metrics = metrics
+ self.cwd = cwd
+ self.metrics = metrics
- def __eq__(self, other):
- if not isinstance(other, Subtest):
- return False
- return self.name == other.name and self.test_name == other.test_name
+ def __eq__(self, other):
+ if not isinstance(other, Subtest):
+ return False
+ return self.name == other.name and self.test_name == other.test_name
+
+ def __str__(self):
+ return yatest_lib.tools.to_utf8(unicode(self))
- def __str__(self):
- return yatest_lib.tools.to_utf8(unicode(self))
-
def __unicode__(self):
return u"{}::{}".format(self.test_name, self.test_name)
@property
def name(self):
- return yatest_lib.tools.to_utf8(self._name)
+ return yatest_lib.tools.to_utf8(self._name)
@property
def test_name(self):
- return yatest_lib.tools.to_utf8(self._test_name)
-
- def __repr__(self):
- return "Subtest [{}::{} - {}[{}]: {}]".format(self.name, self.test_name, self.status, self.elapsed, self.comment)
-
- def __hash__(self):
- return hash(str(self))
-
-
-class SubtestInfo(object):
-
+ return yatest_lib.tools.to_utf8(self._test_name)
+
+ def __repr__(self):
+ return "Subtest [{}::{} - {}[{}]: {}]".format(self.name, self.test_name, self.status, self.elapsed, self.comment)
+
+ def __hash__(self):
+ return hash(str(self))
+
+
+class SubtestInfo(object):
+
skipped_prefix = '[SKIPPED] '
- @classmethod
- def from_str(cls, s):
+ @classmethod
+ def from_str(cls, s):
if s.startswith(SubtestInfo.skipped_prefix):
s = s[len(SubtestInfo.skipped_prefix):]
skipped = True
-
+
else:
skipped = False
return SubtestInfo(*s.rsplit(TEST_SUBTEST_SEPARATOR, 1), skipped=skipped)
def __init__(self, test, subtest="", skipped=False, **kwargs):
- self.test = test
- self.subtest = subtest
+ self.test = test
+ self.subtest = subtest
self.skipped = skipped
- for key, value in kwargs.iteritems():
- setattr(self, key, value)
-
- def __str__(self):
+ for key, value in kwargs.iteritems():
+ setattr(self, key, value)
+
+ def __str__(self):
s = ''
-
+
if self.skipped:
s += SubtestInfo.skipped_prefix
return s + TEST_SUBTEST_SEPARATOR.join([self.test, self.subtest])
- def __repr__(self):
- return str(self)
-
-
+ def __repr__(self):
+ return str(self)
+
+
class Status(object):
GOOD, XFAIL, FAIL, XPASS, MISSING, CRASHED, TIMEOUT = range(7)
- SKIPPED = -100
- NOT_LAUNCHED = -200
- CANON_DIFF = -300
- FLAKY = -1
- BY_NAME = {'good': GOOD, 'fail': FAIL, 'xfail': XFAIL, 'xpass': XPASS, 'missing': MISSING, 'crashed': CRASHED,
- 'skipped': SKIPPED, 'flaky': FLAKY, 'not_launched': NOT_LAUNCHED, 'timeout': TIMEOUT, 'diff': CANON_DIFF}
- TO_STR = {GOOD: 'good', FAIL: 'fail', XFAIL: 'xfail', XPASS: 'xpass', MISSING: 'missing', CRASHED: 'crashed',
- SKIPPED: 'skipped', FLAKY: 'flaky', NOT_LAUNCHED: 'not_launched', TIMEOUT: 'timeout', CANON_DIFF: 'diff'}
+ SKIPPED = -100
+ NOT_LAUNCHED = -200
+ CANON_DIFF = -300
+ FLAKY = -1
+ BY_NAME = {'good': GOOD, 'fail': FAIL, 'xfail': XFAIL, 'xpass': XPASS, 'missing': MISSING, 'crashed': CRASHED,
+ 'skipped': SKIPPED, 'flaky': FLAKY, 'not_launched': NOT_LAUNCHED, 'timeout': TIMEOUT, 'diff': CANON_DIFF}
+ TO_STR = {GOOD: 'good', FAIL: 'fail', XFAIL: 'xfail', XPASS: 'xpass', MISSING: 'missing', CRASHED: 'crashed',
+ SKIPPED: 'skipped', FLAKY: 'flaky', NOT_LAUNCHED: 'not_launched', TIMEOUT: 'timeout', CANON_DIFF: 'diff'}
class Test(object):
- def __init__(self, name, path, status=None, comment=None, subtests=None):
+ def __init__(self, name, path, status=None, comment=None, subtests=None):
self.name = name
self.path = path
- self.status = status
- self.comment = comment
- self.subtests = subtests or []
-
- def __eq__(self, other):
- if not isinstance(other, Test):
- return False
- return self.name == other.name and self.path == other.path
-
- def __str__(self):
- return "Test [{} {}] - {} - {}".format(self.name, self.path, self.status, self.comment)
-
- def __repr__(self):
- return str(self)
-
+ self.status = status
+ self.comment = comment
+ self.subtests = subtests or []
+
+ def __eq__(self, other):
+ if not isinstance(other, Test):
+ return False
+ return self.name == other.name and self.path == other.path
+
+ def __str__(self):
+ return "Test [{} {}] - {} - {}".format(self.name, self.path, self.status, self.comment)
+
+ def __repr__(self):
+ return str(self)
+
def add_subtest(self, subtest):
self.subtests.append(subtest)
@@ -148,10 +148,10 @@ class YaCtx(object):
pass
ya_ctx = YaCtx()
-
-TRACE_FILE_NAME = "ytest.report.trace"
-
-
+
+TRACE_FILE_NAME = "ytest.report.trace"
+
+
def lazy(func):
mem = {}
@@ -174,7 +174,7 @@ def _get_mtab():
def get_max_filename_length(dirname):
- """
+ """
Return maximum filename length for the filesystem
:return:
"""
@@ -194,10 +194,10 @@ def get_unique_file_path(dir_path, filename, cache=collections.defaultdict(set))
"""
Get unique filename in dir with proper filename length, using given filename/dir.
File/dir won't be created (thread nonsafe)
- :param dir_path: path to dir
+ :param dir_path: path to dir
:param filename: original filename
:return: unique filename
- """
+ """
max_suffix = 10000
# + 1 symbol for dot before suffix
tail_length = int(round(math.log(max_suffix, 10))) + 1
@@ -222,83 +222,83 @@ def get_unique_file_path(dir_path, filename, cache=collections.defaultdict(set))
assert counter < max_suffix
candidate = os.path.join(dir_path, filename + ".{}".format(counter))
return candidate
-
-
-def escape_for_fnmatch(s):
- return s.replace("[", "&#91;").replace("]", "&#93;")
-
-
-def get_python_cmd(opts=None, use_huge=True, suite=None):
+
+
+def escape_for_fnmatch(s):
+ return s.replace("[", "&#91;").replace("]", "&#93;")
+
+
+def get_python_cmd(opts=None, use_huge=True, suite=None):
if opts and getattr(opts, 'flags', {}).get("USE_ARCADIA_PYTHON") == "no":
- return ["python"]
- if suite and not suite._use_arcadia_python:
- return ["python"]
+ return ["python"]
+ if suite and not suite._use_arcadia_python:
+ return ["python"]
if use_huge:
return ["$(PYTHON)/python"]
ymake_path = opts.ymake_bin if opts and getattr(opts, 'ymake_bin', None) else "$(YMAKE)/ymake"
return [ymake_path, "--python"]
-
-
-def normalize_name(name):
- replacements = [
- ("\\", "\\\\"),
- ("\n", "\\n"),
- ("\t", "\\t"),
- ("\r", "\\r"),
- ]
- for l, r in replacements:
- name = name.replace(l, r)
- return name
-
-
+
+
+def normalize_name(name):
+ replacements = [
+ ("\\", "\\\\"),
+ ("\n", "\\n"),
+ ("\t", "\\t"),
+ ("\r", "\\r"),
+ ]
+ for l, r in replacements:
+ name = name.replace(l, r)
+ return name
+
+
def normalize_filename(filename):
- """
- Replace invalid for file names characters with string equivalents
- :param some_string: string to be converted to a valid file name
- :return: valid file name
- """
+ """
+ Replace invalid for file names characters with string equivalents
+ :param some_string: string to be converted to a valid file name
+ :return: valid file name
+ """
not_allowed_pattern = r"[\[\]\/:*?\"\'<>|+\0\\\s\x0b\x0c]"
filename = re.sub(not_allowed_pattern, ".", filename)
return re.sub(r"\.{2,}", ".", filename)
-
-
+
+
def get_test_log_file_path(output_dir, class_name, test_name, extension="log"):
- """
- get test log file path, platform dependant
- :param output_dir: dir where log file should be placed
- :param class_name: test class name
- :param test_name: test name
- :return: test log file name
- """
- if os.name == "nt":
+ """
+ get test log file path, platform dependant
+ :param output_dir: dir where log file should be placed
+ :param class_name: test class name
+ :param test_name: test name
+ :return: test log file name
+ """
+ if os.name == "nt":
# don't add class name to the log's filename
# to reduce it's length on windows
filename = test_name
- else:
+ else:
filename = "{}.{}".format(class_name, test_name)
if not filename:
filename = "test"
filename += "." + extension
filename = normalize_filename(filename)
return get_unique_file_path(output_dir, filename)
-
-
-def split_node_id(nodeid, test_suffix=None):
+
+
+def split_node_id(nodeid, test_suffix=None):
path, possible_open_bracket, params = nodeid.partition('[')
- separator = "::"
+ separator = "::"
if separator in path:
path, test_name = path.split(separator, 1)
- else:
- test_name = os.path.basename(path)
- if test_suffix:
- test_name += "::" + test_suffix
- class_name = os.path.basename(path.strip())
- if separator in test_name:
- klass_name, test_name = test_name.split(separator, 1)
- if not test_suffix:
- # test suffix is used for flakes and pep8, no need to add class_name as it's === class_name
- class_name += separator + klass_name
- if separator in test_name:
- test_name = test_name.split(separator)[-1]
+ else:
+ test_name = os.path.basename(path)
+ if test_suffix:
+ test_name += "::" + test_suffix
+ class_name = os.path.basename(path.strip())
+ if separator in test_name:
+ klass_name, test_name = test_name.split(separator, 1)
+ if not test_suffix:
+ # test suffix is used for flakes and pep8, no need to add class_name as it's === class_name
+ class_name += separator + klass_name
+ if separator in test_name:
+ test_name = test_name.split(separator)[-1]
test_name += possible_open_bracket + params
- return yatest_lib.tools.to_utf8(class_name), yatest_lib.tools.to_utf8(test_name)
+ return yatest_lib.tools.to_utf8(class_name), yatest_lib.tools.to_utf8(test_name)