1
0
Fork 1
mirror of https://gitlab.postmarketos.org/postmarketOS/pmbootstrap.git synced 2025-07-12 19:09:56 +03:00
pmbootstrap/test/conftest.py
Hugo Osvaldo Barrera 5a152aebae
test: move all tests into separate module (MR 2551)
When installing pmboostrap, all tests are installed alongside it. There
doesn't seem to be any way to selectively exclude some files inside
python modules, so move all test into a separate module instead.

This is the typical convention in python projects.

See: https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/79862
Fixes: https://gitlab.postmarketos.org/postmarketOS/pmbootstrap/-/issues/2541
2025-02-13 01:28:20 +01:00

190 lines
5.3 KiB
Python

# Copyright 2024 Caleb Connolly
# SPDX-License-Identifier: GPL-3.0-or-later
import os
from pathlib import Path
import pytest
import shutil
import tempfile
import pmb.core
from pmb.core.context import get_context
from pmb.types import PmbArgs
from pmb.helpers.args import init as init_args
_testdir = Path(__file__).parent / "data/tests"
# request can be specified using parameterize from test cases
# e.g. @pytest.mark.parametrize("config_file", ["no-repos"], indirect=True)
# will set request.param to "no-repos"
@pytest.fixture
def config_file(tmp_path_factory, request):
"""Fixture to create a temporary pmbootstrap_v3.cfg file."""
tmp_path = tmp_path_factory.mktemp("pmbootstrap")
flavour = "default"
if hasattr(request, "param") and request.param:
flavour = request.param
out_file = tmp_path / "pmbootstrap_v3.cfg"
workdir = tmp_path / "work"
workdir.mkdir()
configs = {"default": f"aports = {workdir / 'cache_git' / 'pmaports'}", "no-repos": "aports = "}
file = _testdir / "pmbootstrap_v3.cfg"
print(f"CONFIG: {out_file}")
cfg = configs[flavour]
contents = open(file).read().format(workdir, cfg)
open(out_file, "w").write(contents)
return out_file
@pytest.fixture
def device_package(config_file):
"""Fixture to create a temporary deviceinfo file."""
mock_device = "qemu-amd64"
pkgdir = config_file.parent / f"device-{mock_device}"
pkgdir.mkdir()
for file in ["APKBUILD", "deviceinfo"]:
shutil.copy(_testdir / f"{file}.{mock_device}", pkgdir / file)
return pkgdir
@pytest.fixture(autouse=True)
def find_required_programs():
"""Fixture to find required programs for pmbootstrap."""
pmb.config.require_programs()
@pytest.fixture
def mock_devices_find_path(device_package, monkeypatch):
"""Fixture to mock pmb.helpers.devices.find_path()"""
def mock_find_path(device, file=""):
print(f"mock_find_path({device}, {file})")
out = device_package / file
if not out.exists():
return None
return out
monkeypatch.setattr("pmb.helpers.devices.find_path", mock_find_path)
@pytest.fixture(autouse=True)
def logfile(tmp_path_factory):
"""Setup logging for all tests."""
from pmb.helpers import logging
tmp_path = tmp_path_factory.getbasetemp()
logfile = tmp_path / "log_testsuite.txt"
logging.init(logfile, verbose=True)
return logfile
@pytest.fixture(autouse=True)
def setup_mock_ask(monkeypatch):
"""Common setup to mock cli.ask() to avoid reading from stdin"""
import pmb.helpers.cli
def mock_ask(
question="Continue?",
choices=["y", "n"],
default="n",
lowercase_answer=True,
validation_regex=None,
complete=None,
):
return default
monkeypatch.setattr(pmb.helpers.cli, "ask", mock_ask)
# FIXME: get/set_context() is a bad hack :(
@pytest.fixture
def mock_context(monkeypatch):
"""Mock set_context() to bypass sanity checks. Ideally we would
mock get_context() as well, but since every submodule of pmb imports
it like "from pmb.core.context import get_context()", we can't
actually override it with monkeypatch.setattr(). So this is the
best we can do... set_context() is only called from one place and is
done so with the full namespace, so this works."""
def mock_set_context(ctx):
print(f"mock_set_context({ctx})")
setattr(pmb.core.context, "__context", ctx)
monkeypatch.setattr("pmb.core.context.set_context", mock_set_context)
# FIXME: get_context() at runtime somehow doesn't return the
# custom context we set up here.
@pytest.fixture
def pmb_args(config_file, mock_context, logfile):
"""This is (still) a hack, since a bunch of the codebase still
expects some global state to be initialised. We do that here."""
args = PmbArgs()
args.config = config_file
args.aports = None
args.timeout = 900
args.details_to_stdout = False
args.quiet = False
args.verbose = True
args.offline = False
args.action = "init"
args.cross = False
args.log = logfile
init_args(args)
print(f"WORK: {get_context().config.work}")
# Sanity check
assert ".pytest_tmp" in get_context().config.work.parts
@pytest.fixture
def foreign_arch():
"""Fixture to return the foreign arch."""
from pmb.core.arch import Arch
if os.uname().machine == "x86_64":
return Arch.aarch64
return Arch.x86_64
@pytest.fixture
def pmaports(pmb_args, monkeypatch):
"""Fixture to clone pmaports."""
from pmb.core import Config
from pmb.core.context import get_context
cfg = get_context().config
# As an optimisation, we check the default workdir for pmaports
# and clone it from there if it exists. This saves a bunch of bandwidth
# and time.
if Config.aports[-1].exists():
# Override the URL to the local path so we can later look up the
# remote by URL
pmb.config.git_repos["pmaports"] = [str(Config.aports[-1])]
if not cfg.aports[-1].exists():
pmb.helpers.git.clone("pmaports")
# Now operate on the cloned repo
assert pmb.helpers.run.user(["git", "checkout", "master"], working_dir=cfg.aports[-1]) == 0
@pytest.fixture
def tmp_file(tmp_path):
return Path(tempfile.mkstemp(dir=tmp_path)[1])