aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCédric Ollivier <cedric.ollivier@orange.com>2023-03-31 15:52:21 +0200
committerCédric Ollivier <cedric.ollivier@orange.com>2023-04-14 16:05:50 +0200
commit12732b13c55eb91f32ed65f1d8a1f72b4aa2c534 (patch)
tree38d780ee4126de59392f893157b03c4fb37c602d
parentfd8498598096cabb991cf3494220a9715d3360f7 (diff)
Add pytest driver in Xtesting
Co-authored-by: Edouard Hinard <edouard.hinard@orange.com> Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com> Change-Id: Ice364f7f4287aacc7f375ed4a23503fd38c8e543
-rw-r--r--api/apidoc/xtesting.core.pytest.rst7
-rw-r--r--api/apidoc/xtesting.core.rst1
-rw-r--r--docker/core/testcases.yaml11
-rw-r--r--requirements.txt2
-rw-r--r--setup.cfg1
-rw-r--r--test-requirements.txt2
-rw-r--r--upper-constraints.txt3
-rw-r--r--xtesting/ci/testcases.yaml11
-rw-r--r--xtesting/core/pytest.py101
9 files changed, 134 insertions, 5 deletions
diff --git a/api/apidoc/xtesting.core.pytest.rst b/api/apidoc/xtesting.core.pytest.rst
new file mode 100644
index 00000000..fcc649f7
--- /dev/null
+++ b/api/apidoc/xtesting.core.pytest.rst
@@ -0,0 +1,7 @@
+xtesting\.core\.pytest module
+=============================
+
+.. automodule:: xtesting.core.pytest
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/api/apidoc/xtesting.core.rst b/api/apidoc/xtesting.core.rst
index 5707a28c..30276712 100644
--- a/api/apidoc/xtesting.core.rst
+++ b/api/apidoc/xtesting.core.rst
@@ -15,6 +15,7 @@ Submodules
xtesting.core.behaveframework
xtesting.core.campaign
xtesting.core.feature
+ xtesting.core.pytest
xtesting.core.robotframework
xtesting.core.testcase
xtesting.core.unit
diff --git a/docker/core/testcases.yaml b/docker/core/testcases.yaml
index 360869d4..deee73b6 100644
--- a/docker/core/testcases.yaml
+++ b/docker/core/testcases.yaml
@@ -78,3 +78,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/requirements.txt b/requirements.txt
index 71596528..1db79684 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -17,3 +17,5 @@ junitxml
boto3 # Apache-2.0
lxml!=3.7.0 # BSD
ansible-runner!=1.3.5 # Apache 2.0
+pytest # MIT
+pytest-html #MPL-2.0
diff --git a/setup.cfg b/setup.cfg
index 944e2d0f..06ff9950 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -31,6 +31,7 @@ xtesting.testcase =
second = xtesting.samples.second:Test
mts = xtesting.core.mts:MTSLauncher
ansible = xtesting.core.ansible:Ansible
+ pytest = xtesting.core.pytest:Pytest
[build_sphinx]
all_files = 1
diff --git a/test-requirements.txt b/test-requirements.txt
index 4be1d670..22457d0f 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -3,8 +3,6 @@
# process, which may cause wedges in the gate later.
coverage!=4.4 # Apache-2.0
mock!=4.0.0,!=4.0.1 # BSD
-pytest # MIT
-pytest-html #MPL-2.0
pytest-cov
flake8 # MIT
pylint # GPLv2
diff --git a/upper-constraints.txt b/upper-constraints.txt
index 59d9f4d5..e15894aa 100644
--- a/upper-constraints.txt
+++ b/upper-constraints.txt
@@ -5,7 +5,4 @@ behave-html-formatter===0.9.8
pylint===2.11.1
flake8===4.0.1
ansible-lint===5.2.1
-pytest===7.1.2
-pytest-cov===3.0.0
-pytest-html===3.1.1
pre-commit===3.1.1
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