From cd6d72b1ce4001d4700d095b0c1fd2f92a822bb6 Mon Sep 17 00:00:00 2001 From: Cédric Ollivier Date: Fri, 31 Mar 2023 15:52:21 +0200 Subject: Add pytest driver in Xtesting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Edouard Hinard Signed-off-by: Cédric Ollivier Change-Id: Ice364f7f4287aacc7f375ed4a23503fd38c8e543 (cherry picked from commit 12732b13c55eb91f32ed65f1d8a1f72b4aa2c534) --- xtesting/ci/testcases.yaml | 11 +++++ xtesting/core/pytest.py | 101 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 xtesting/core/pytest.py (limited to 'xtesting') diff --git a/xtesting/ci/testcases.yaml b/xtesting/ci/testcases.yaml index ead3441c..488bf953 100644 --- a/xtesting/ci/testcases.yaml +++ b/xtesting/ci/testcases.yaml @@ -99,3 +99,14 @@ tiers: args: private_data_dir: /usr/lib/python3.10/site-packages/xtesting/samples playbook: helloworld.yml + - case_name: nineth + project_name: xtesting + enabled: true + criteria: 100 + blocking: true + clean_flag: false + description: '' + run: + name: pytest + args: + dir: /usr/lib/python3.10/site-packages/xtesting/samples/fourth.py diff --git a/xtesting/core/pytest.py b/xtesting/core/pytest.py new file mode 100644 index 00000000..1dadf300 --- /dev/null +++ b/xtesting/core/pytest.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python + +# Copyright (c) 2023 Orange and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 + +"""Define classes required to run any Pytest suites.""" + +import contextlib +import io +import logging +import time + +import pytest + +from xtesting.core import testcase + + +@pytest.hookimpl(hookwrapper=True) +def pytest_runtest_makereport(item, call): + """Collect all Pytest results""" + # pylint: disable=unused-argument + yreport = yield + report = yreport.get_result() + if report.when == 'call': + test = {"name": report.nodeid, "status": report.outcome.upper()} + if report.passed: + Pytest.passed += 1 + elif report.failed: + Pytest.failed += 1 + test['failure'] = report.longreprtext + Pytest.tests.append(test) + + +class Pytest(testcase.TestCase): + + """Pytest driver + + The pytest driver can be used on every test set written for pytest. + Given a pytest package that is launched with the command: + + .. code-block:: shell + + pytest --opt1 arg1 --opt2 testdir + + it can be executed by xtesting with the following testcase.yaml: + + .. code-block:: yaml + + run: + name: pytest + args: + opt1: arg1 + opt2: arg2 + """ + + __logger = logging.getLogger(__name__) + tests = [] + passed = 0 + failed = 0 + + def run(self, **kwargs): + # parsing args + # - 'dir' is mandatory + # - 'options' is an optional list or a dict flatten to a list + status = self.EX_RUN_ERROR + self.start_time = time.time() + try: + pydir = kwargs.pop('dir') + options = kwargs.pop('options', {}) + options['html'] = f'{self.res_dir}/results.html' + options['junitxml'] = f'{self.res_dir}/results.xml' + if 'tb' not in options: + options['tb'] = 'no' + options = [ + str(item) for opt in zip( + [f'--{k}' if len(str(k)) > 1 else + f'-{k}' for k in options.keys()], + options.values()) + for item in opt if item is not None] + with contextlib.redirect_stdout(io.StringIO()) as output: + pytest.main( + args=[pydir] + ['-p', __name__] + options) + with open(f'{self.res_dir}/stdout.log', + 'w', encoding='utf-8') as output_file: + output_file.write(output.getvalue()) + self.__logger.info( + "\n\n %s \n", + output.getvalue().splitlines()[-1].replace('=', '')) + self.details = Pytest.tests + if Pytest.passed + Pytest.failed: + self.result = Pytest.passed / ( + Pytest.passed + Pytest.failed) * 100 + status = self.EX_OK + except Exception: # pylint: # pylint: disable=broad-except + self.__logger.exception("Cannot execute pytest") + self.stop_time = time.time() + return status -- cgit 1.2.3-korg