mirror of
https://gitlab.postmarketos.org/postmarketOS/pmbootstrap.git
synced 2025-07-12 19:09:56 +03:00
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
190 lines
5.3 KiB
Python
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])
|