Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CP-48198: Fix running pytest on tests/integration in GitHub CI (with coverage) #105

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[run]
command_line = -m pytest --junitxml=.git/pytest.xml --cov-report=term-missing tests/unit
command_line = -m pytest --junitxml=.git/pytest.xml --cov-report=term-missing
# Default data file for "coverage run": Store coverage data in .git/.coverage
data_file = .git/.coverage
relative_files = True
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ jobs:
run: |
if [ -f requirements.txt ]; then pip2 install -r requirements.txt; fi
if [ -f requirements-dev.txt ]; then pip2 install -r requirements-dev.txt; fi
pip2 install pylint==1.9.4
pip2 install pylint==1.9.4; sudo mkdir /opt/xensource # mountpoint for tests

- name: Run pylint-1.9.4 for pylint --py3k linting (configured in .pylintrc)
run: python2 -m pylint xen-bugtool
Expand Down Expand Up @@ -146,7 +146,7 @@ jobs:
python-version: '3.10'
cache: 'pip'

- run: pip install -r requirements-dev.txt
- run: pip install -r requirements-dev.txt; sudo mkdir /opt/xensource
name: Install the pytest dependencies for running the pytest suite using Python3

- uses: actions/cache@v4
Expand Down
39 changes: 39 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""tests/conftest.py: top-level pytest fixtures for testing xen-bugtool

Introduction to fixtures:
https://docs.pytest.org/en/8.0.x/fixture.html

How to use fixtures:
https://docs.pytest.org/en/8.0.x/how-to/fixtures.html

The full documentation on fixtures:
https://docs.pytest.org/en/8.0.x/reference/fixtures.html
"""

import os

import pytest


@pytest.fixture(scope="session")
def tests_dir():
"""pytest fixture to provide the path to status-report/tests"""
return os.path.dirname(__file__)


@pytest.fixture(scope="session")
def bugtool_script(tests_dir):
"""pytest fixture to provide the path to status-report/tests"""
return os.path.abspath(os.path.join(tests_dir, os.pardir, "xen-bugtool"))


@pytest.fixture(scope="session")
def mocks_dir(tests_dir):
"""pytest fixture to provide the path to status-report/tests/mocks"""
return os.path.join(tests_dir, "mocks")


@pytest.fixture(scope="session")
def dom0_template(tests_dir):
"""Fixture to provide the path to status-report/tests/integration/dom0-template"""
return os.path.join(tests_dir, "integration", "dom0-template")
15 changes: 12 additions & 3 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from __future__ import print_function

import os
import sys

import pytest

Expand All @@ -18,10 +19,18 @@


@pytest.fixture(autouse=True, scope="session")
def create_and_enter_test_environment():
def create_and_enter_test_environment(mocks_dir):
"""Activate a namespace with bind mounts for testing xen-bugtool"""
activate_private_test_namespace(BUGTOOL_DOM0_TEMPL, ["/etc", "/opt", "/usr/sbin", "/usr/lib/systemd"])
os.environ["PYTHONPATH"] = "tests/mocks"

activate_private_test_namespace(
BUGTOOL_DOM0_TEMPL,
["/etc", "/opt/xensource", "/usr/sbin", "/usr/lib/systemd"],
)

# Add the mocks directory to the PYTHONPATH for sub-processes to find the mocks:
os.environ["PYTHONPATH"] = mocks_dir
# Add the mocks directory to the sys.path for the current process to find the mocks:
sys.path.insert(0, mocks_dir)


# zip, tar, tar.bz2 are the three output formats supported by xen_bugtool:
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/test_system_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

# In this test case we need to sleep for 1 sec, and it is sufficient
# to test to only with zip archives to keep the test duration short:
def test_system_load(output_archive_type="zip"):
def test_system_load(bugtool_script, output_archive_type="zip"):
"""Test xen-bugtool --entries=system-load"""

entry = "system-load"
Expand All @@ -30,7 +30,7 @@ def test_system_load(output_archive_type="zip"):
sar.write("#!/bin/sh\nsleep 1;cat /etc/xensource-inventory\n")
os.chmod("/var/sar", 0o777) # nosec

run_bugtool_entry(output_archive_type, entry)
run_bugtool_entry(bugtool_script, output_archive_type, entry)

assert_content_from_dom0_template("sar-A.out", "etc/xensource-inventory")
assert_file("var/log/sa/sa01", "sa01 test data")
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/test_xenserver_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
)


def test_xenserver_config(output_archive_type):
def test_xenserver_config(bugtool_script, output_archive_type):
"""
Run xen-bugtool --entries=xenserver-config in test jail
(created by auto-fixtures, see README-pytest-chroot.md)
"""
entry = "xenserver-config"

run_bugtool_entry(output_archive_type, entry)
run_bugtool_entry(bugtool_script, output_archive_type, entry)

# Check the output of xen-bugtool --entries=xenserver-config:

Expand Down
42 changes: 17 additions & 25 deletions tests/integration/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import filecmp
import os
import runpy
import shutil
import sys
import tarfile
Expand All @@ -12,14 +13,8 @@

from lxml.etree import XMLSchema, parse # pytype: disable=import-error

# pyright: ignore[reportMissingImports]
if sys.version_info.major == 2: # pragma: no cover
from commands import getstatusoutput # type:ignore[import-not-found]
else:
from subprocess import getstatusoutput

BUGTOOL_OUTPUT_DIR = "/var/opt/xen/bug-report/"
BUGTOOL_DOM0_TEMPL = "tests/integration/dom0-template/"
BUGTOOL_DOM0_TEMPL = os.path.join(os.path.dirname(__file__), "dom0-template")


def run(command):
Expand Down Expand Up @@ -78,7 +73,7 @@ def assert_content_from_dom0_template(path, control_path=None):
"""Check the given path against the files from the test's Dom0 template"""

assert path[0] != "/" # We expect a relative path in the report archive
control = BUGTOOL_DOM0_TEMPL + (control_path or path)
control = os.path.join(BUGTOOL_DOM0_TEMPL, (control_path or path))
print(control)
if os.path.isdir(path):
# path is a directory, compare it recursively using dircmp():
Expand Down Expand Up @@ -126,7 +121,7 @@ def extract(zip_or_tar_archive, archive_type): # pragma: no cover
os.unlink(zip_or_tar_archive)


def run_bugtool_entry(archive_type, test_entries):
def run_bugtool_entry(bugtool_script, archive_type, test_entries):
"""
Execute the bugtool script with the given entries and prepare testing it.

Expand All @@ -138,19 +133,18 @@ def run_bugtool_entry(archive_type, test_entries):

os.environ["XENRT_BUGTOOL_BASENAME"] = test_entries

command = "python%s ./xen-bugtool -y --output=%s --entries=%s" % (
sys.version_info.major,
archive_type,
test_entries,
)
print("# " + command)
error_code, output = getstatusoutput(command)

print(output)
if error_code:
raise RuntimeError(output)

src_dir = os.getcwd()
sys.argv = [
"xen-bugtool",
"-y",
"--output=%s" % archive_type,
"--entries=%s" % test_entries,
]
print(" ".join(sys.argv))
try:
runpy.run_path(bugtool_script, run_name="__main__")
except SystemExit as e:
if e.code: # pylint: disable=using-constant-test # pragma: no cover
raise

#
# Switch to the BUGTOOL_OUTPUT_DIR and extract the bugball in it.
Expand All @@ -166,9 +160,7 @@ def run_bugtool_entry(archive_type, test_entries):
os.chdir(test_entries)

# Validate the extracted inventory.xml using the XML schema from the test framework:
with open(src_dir + "/tests/integration/inventory.xsd") as xml_schema:
with open(os.path.join(os.path.dirname(__file__), "inventory.xsd")) as xml_schema:
XMLSchema(parse(xml_schema)).assertValid(parse("inventory.xml"))
# Remove valid inventory.xml (not removed files will make the tests fail):
os.unlink("inventory.xml")
# Add a symlink, so assert_content_from_dom0_template() can find the tests:
os.symlink(src_dir + "/tests", "tests")
6 changes: 0 additions & 6 deletions tests/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,6 @@ def testdir():
return os.path.dirname(__file__)


@pytest.fixture(scope="session")
def dom0_template(testdir):
"""Test fixture to get the directory of the dom0 template"""
return testdir + "/../integration/dom0-template"


@pytest.fixture(scope="session")
def imported_bugtool(testdir, dom0_template):
"""Fixture to provide the xen-bugtool script as a module for unit tests"""
Expand Down
5 changes: 4 additions & 1 deletion tests/unit/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,10 @@ def assert_bugtool_logfile_data(logfile):
# caught and logged, the log file should contain the backtrace from the
# raised exception:
#
assert len(lines) == 9
if sys.version_info >= (3, 11): # pragma: no cover
assert len(lines) == 10 # Python 3.11+ includes a new line in the backtrace
else:
assert len(lines) == 9
for backtrace_string in MOCK_EXCEPTION_STRINGS:
assert backtrace_string in log

Expand Down
3 changes: 2 additions & 1 deletion tests/unit/test_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ def mock_data_collector(capability):
def assert_valid_inventory_schema(inventory_tree):
"""Assert that the passed inventory validates against the inventory schema"""

with open(os.getcwd() + "/tests/integration/inventory.xsd") as xml_schema:
inventory_schema = os.path.dirname(__file__) + "/../integration/inventory.xsd"
with open(inventory_schema) as xml_schema:
XMLSchema(parse(xml_schema)).assertValid(inventory_tree)


Expand Down
Loading