diff --git a/allure-pytest/src/listener.py b/allure-pytest/src/listener.py index cdcc38e3..55e444a7 100644 --- a/allure-pytest/src/listener.py +++ b/allure-pytest/src/listener.py @@ -14,7 +14,7 @@ from allure_commons.model2 import Parameter from allure_commons.model2 import Label, Link from allure_commons.model2 import Status -from allure_commons.types import LabelType +from allure_commons.types import LabelType, AttachmentType from allure_pytest.utils import allure_description, allure_description_html from allure_pytest.utils import allure_labels, allure_links, pytest_markers from allure_pytest.utils import allure_full_name, allure_package, allure_name @@ -185,6 +185,12 @@ def pytest_runtest_makereport(self, item, call): test_result.status = status test_result.statusDetails = status_details + if self.config.option.attach_capture: + # Capture at teardown contains data from whole test (setup, call, teardown) + self.attach_data(report.caplog, "log", AttachmentType.TEXT, None) + self.attach_data(report.capstdout, "stdout", AttachmentType.TEXT, None) + self.attach_data(report.capstderr, "stderr", AttachmentType.TEXT, None) + uuid = self._cache.pop(item.nodeid) self.allure_logger.close_test(uuid) diff --git a/allure-pytest/src/plugin.py b/allure-pytest/src/plugin.py index 22af5fd4..30558045 100644 --- a/allure-pytest/src/plugin.py +++ b/allure-pytest/src/plugin.py @@ -24,6 +24,11 @@ def pytest_addoption(parser): dest="clean_alluredir", help="Clean alluredir folder if it exists") + parser.getgroup("reporting").addoption('--allure-no-capture', + action="store_false", + dest="attach_capture", + help="Do not attach pytest captured logging/stdout/stderr to report") + def label_type(type_name, legal_values=set()): def a_label_type(string): atoms = set(string.split(',')) diff --git a/allure-pytest/test/capture_integration/test_attach_capture.py.off b/allure-pytest/test/capture_integration/test_attach_capture.py.off new file mode 100644 index 00000000..f8b834d3 --- /dev/null +++ b/allure-pytest/test/capture_integration/test_attach_capture.py.off @@ -0,0 +1,154 @@ +import logging +import pytest + + +logger = logging.getLogger(__name__) + + +@pytest.fixture +def fix1(): + # Just for checking capture in fixtures + print("fix setup") + logger.info("fix setup") + yield + logger.info("fix teardown") + print("fix teardown") + + +### These tests really need to be parametrized, how to do it with doctest? ### + + +def test_capture_stdout_logs_fd(fix1): + """ + >>> import os + >>> allure_report = getfixture('allure_report_with_params')('--log-cli-level=INFO') + + >>> attachment_names = [] + + >>> test = None + >>> for item in allure_report.test_cases: + ... if item["name"] == "test_capture_stdout_logs_fd": + ... test = item + + >>> for attachment in test["attachments"]: + ... name = attachment["name"] + ... source = os.path.join(allure_report.result_dir, attachment["source"]) + ... attachment_names.append(name) + ... if name == "stdout": + ... with open(source, "r") as f: + ... capstdout = f.read() + ... assert "fix setup" in capstdout + ... assert "begin test" in capstdout + ... assert "end test" in capstdout + ... assert "fix teardown" in capstdout + ... elif name == "log": + ... with open(source, "r") as f: + ... caplog = f.read() + ... assert "fix setup" in caplog + ... assert "something in test" in caplog + ... assert "fix teardown" in caplog + + >>> assert "stdout" in attachment_names + >>> assert "stderr" in attachment_names + >>> assert "log" in attachment_names + """ + print("begin test") + logger.info("something in test") + print("end test") + + +def test_capture_stdout_no_logs(fix1): + """ + >>> import os + >>> allure_report = getfixture('allure_report_with_params')('--log-cli-level=INFO', '-p no:logging') + + >>> attachment_names = [] + + >>> test = None + >>> for item in allure_report.test_cases: + ... if item["name"] == "test_capture_stdout_no_logs": + ... test = item + + >>> for attachment in test["attachments"]: + ... name = attachment["name"] + ... source = os.path.join(allure_report.result_dir, attachment["source"]) + ... attachment_names.append(name) + ... if name == "stdout": + ... with open(source, "r") as f: + ... capstdout = f.read() + ... assert "fix setup" in capstdout + ... assert "begin test" in capstdout + ... assert "end test" in capstdout + ... assert "fix teardown" in capstdout + ... elif name == "log": + ... with open(source, "r") as f: + ... caplog = f.read() + ... assert caplog == "" + + >>> assert "stdout" in attachment_names + >>> assert "stderr" in attachment_names + >>> assert "log" in attachment_names + """ + print("begin test") + logger.info("something in test") + print("end test") + + +def test_capture_stdout_logs_sys(fix1): + """ + >>> import os + >>> allure_report = getfixture('allure_report_with_params')('--log-cli-level=INFO', '--capture=sys') + + >>> attachment_names = [] + + >>> test = None + >>> for item in allure_report.test_cases: + ... if item["name"] == "test_capture_stdout_logs_sys": + ... test = item + + >>> with open("DOCTDEBUG", "w") as file: + ... a = file.write("{{{}}}\\n{{{}}}".format(test.keys(), test)) + + >>> for attachment in test["attachments"]: + ... name = attachment["name"] + ... source = os.path.join(allure_report.result_dir, attachment["source"]) + ... attachment_names.append(name) + ... if name == "stdout": + ... with open(source, "r") as f: + ... capstdout = f.read() + ... assert "fix setup" in capstdout + ... assert "begin test" in capstdout + ... assert "end test" in capstdout + ... assert "fix teardown" in capstdout + ... elif name == "log": + ... with open(source, "r") as f: + ... caplog = f.read() + ... assert "fix setup" in caplog + ... assert "something in test" in caplog + ... assert "fix teardown" in caplog + + >>> assert "stdout" in attachment_names + >>> assert "stderr" in attachment_names + >>> assert "log" in attachment_names + """ + print("begin test") + logger.info("something in test") + print("end test") + + +def test_capture_disabled(fix1): + """ + >>> allure_report = getfixture('allure_report_with_params')('--log-cli-level=INFO', '--allure-no-capture') + + >>> attachment_names = [] + + >>> test = None + >>> for item in allure_report.test_cases: + ... if item["name"] == "test_capture_disabled": + ... test = item + + >>> assert "attachments" not in test + """ + print("begin test") + logger.info("something in test") + print("end test") diff --git a/allure-pytest/test/capture_integration/test_attach_capture_disabled.py b/allure-pytest/test/capture_integration/test_attach_capture_disabled.py new file mode 100644 index 00000000..f5a7ecf0 --- /dev/null +++ b/allure-pytest/test/capture_integration/test_attach_capture_disabled.py @@ -0,0 +1,33 @@ +import logging +import pytest + + +logger = logging.getLogger(__name__) + + +@pytest.fixture +def fix1(): + # Just for checking capture in fixtures + print("fix setup") + logger.info("fix setup") + yield + logger.info("fix teardown") + print("fix teardown") + + +def test_capture_disabled(fix1): + """ + >>> allure_report = getfixture('allure_report_with_params')('--log-cli-level=INFO', '--allure-no-capture') + + >>> attachment_names = [] + + >>> test = None + >>> for item in allure_report.test_cases: + ... if item["name"] == "test_capture_disabled": + ... test = item + + >>> assert "attachments" not in test + """ + print("begin test") + logger.info("something in test") + print("end test") diff --git a/allure-pytest/test/capture_integration/test_attach_capture_fd.py b/allure-pytest/test/capture_integration/test_attach_capture_fd.py new file mode 100644 index 00000000..81492f17 --- /dev/null +++ b/allure-pytest/test/capture_integration/test_attach_capture_fd.py @@ -0,0 +1,55 @@ +import logging +import pytest + + +logger = logging.getLogger(__name__) + + +@pytest.fixture +def fix1(): + # Just for checking capture in fixtures + print("fix setup") + logger.info("fix setup") + yield + logger.info("fix teardown") + print("fix teardown") + + +def test_capture_stdout_logs_fd(fix1): + """ + >>> import os + >>> allure_report = getfixture('allure_report_with_params')('--log-cli-level=INFO') + + >>> attachment_names = [] + + >>> test = None + >>> for item in allure_report.test_cases: + ... if item["name"] == "test_capture_stdout_logs_fd": + ... test = item + + >>> for attachment in test["attachments"]: + ... name = attachment["name"] + ... source = os.path.join(allure_report.result_dir, attachment["source"]) + ... attachment_names.append(name) + ... if name == "stdout": + ... with open(source, "r") as f: + ... capstdout = f.read() + ... assert "fix setup" in capstdout + ... assert "begin test" in capstdout + ... assert "end test" in capstdout + ... assert "fix teardown" in capstdout + ... elif name == "log": + ... with open(source, "r") as f: + ... caplog = f.read() + ... assert "fix setup" in caplog + ... assert "something in test" in caplog + ... assert "fix teardown" in caplog + + >>> assert "stdout" in attachment_names + >>> assert "stderr" in attachment_names + >>> assert "log" in attachment_names + """ + print("begin test") + logger.info("something in test") + print("end test") + diff --git a/allure-pytest/test/capture_integration/test_attach_capture_no_logs.py b/allure-pytest/test/capture_integration/test_attach_capture_no_logs.py new file mode 100644 index 00000000..c8782724 --- /dev/null +++ b/allure-pytest/test/capture_integration/test_attach_capture_no_logs.py @@ -0,0 +1,53 @@ +import logging +import pytest + + +logger = logging.getLogger(__name__) + + +@pytest.fixture +def fix1(): + # Just for checking capture in fixtures + print("fix setup") + logger.info("fix setup") + yield + logger.info("fix teardown") + print("fix teardown") + + +def test_capture_stdout_no_logs(fix1): + """ + >>> import os + >>> allure_report = getfixture('allure_report_with_params')('--log-cli-level=INFO', '-p no:logging') + + >>> attachment_names = [] + + >>> test = None + >>> for item in allure_report.test_cases: + ... if item["name"] == "test_capture_stdout_no_logs": + ... test = item + + >>> for attachment in test["attachments"]: + ... name = attachment["name"] + ... source = os.path.join(allure_report.result_dir, attachment["source"]) + ... attachment_names.append(name) + ... if name == "stdout": + ... with open(source, "r") as f: + ... capstdout = f.read() + ... assert "fix setup" in capstdout + ... assert "begin test" in capstdout + ... assert "end test" in capstdout + ... assert "fix teardown" in capstdout + ... elif name == "log": + ... with open(source, "r") as f: + ... caplog = f.read() + ... assert caplog == "" + + >>> assert "stdout" in attachment_names + >>> assert "stderr" in attachment_names + >>> assert "log" in attachment_names + """ + print("begin test") + logger.info("something in test") + print("end test") + diff --git a/allure-pytest/test/capture_integration/test_attach_capture_sys.py b/allure-pytest/test/capture_integration/test_attach_capture_sys.py new file mode 100644 index 00000000..b3b6f089 --- /dev/null +++ b/allure-pytest/test/capture_integration/test_attach_capture_sys.py @@ -0,0 +1,57 @@ +import logging +import pytest + + +logger = logging.getLogger(__name__) + + +@pytest.fixture +def fix1(): + # Just for checking capture in fixtures + print("fix setup") + logger.info("fix setup") + yield + logger.info("fix teardown") + print("fix teardown") + + +def test_capture_stdout_logs_sys(fix1): + """ + >>> import os + >>> allure_report = getfixture('allure_report_with_params')('--log-cli-level=INFO', '--capture=sys') + + >>> attachment_names = [] + + >>> test = None + >>> for item in allure_report.test_cases: + ... if item["name"] == "test_capture_stdout_logs_sys": + ... test = item + + >>> with open("DOCTDEBUG", "w") as file: + ... a = file.write("{{{}}}\\n{{{}}}".format(test.keys(), test)) + + >>> for attachment in test["attachments"]: + ... name = attachment["name"] + ... source = os.path.join(allure_report.result_dir, attachment["source"]) + ... attachment_names.append(name) + ... if name == "stdout": + ... with open(source, "r") as f: + ... capstdout = f.read() + ... assert "fix setup" in capstdout + ... assert "begin test" in capstdout + ... assert "end test" in capstdout + ... assert "fix teardown" in capstdout + ... elif name == "log": + ... with open(source, "r") as f: + ... caplog = f.read() + ... assert "fix setup" in caplog + ... assert "something in test" in caplog + ... assert "fix teardown" in caplog + + >>> assert "stdout" in attachment_names + >>> assert "stderr" in attachment_names + >>> assert "log" in attachment_names + """ + print("begin test") + logger.info("something in test") + print("end test") diff --git a/allure-python-commons-test/src/report.py b/allure-python-commons-test/src/report.py index c79cab0d..28bda7a0 100644 --- a/allure-python-commons-test/src/report.py +++ b/allure-python-commons-test/src/report.py @@ -83,6 +83,7 @@ class AllureReport(object): def __init__(self, result): + self.result_dir = result self.test_cases = [json.load(item) for item in self._report_items(result, '*result.json')] self.test_containers = [json.load(item) for item in self._report_items(result, '*container.json')] self.attachments = [item.read() for item in self._report_items(result, '*attachment.*')]