File: conftest.py

package info (click to toggle)
pmbootstrap 3.9.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,864 kB
  • sloc: python: 17,395; sh: 425; makefile: 17
file content (194 lines) | stat: -rw-r--r-- 5,871 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# Copyright 2024 Caleb Connolly
# SPDX-License-Identifier: GPL-3.0-or-later

import shutil
import tempfile
from pathlib import Path

import pytest
from _pytest.fixtures import FixtureRequest
from _pytest.monkeypatch import MonkeyPatch
from _pytest.tmpdir import TempPathFactory

import pmb.core
from pmb.core.arch import Arch
from pmb.core.context import Context, get_context
from pmb.helpers.args import init as init_args
from pmb.types import PmbArgs

_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: TempPathFactory, request: FixtureRequest) -> Path:
    """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 = file.read_text().format(workdir, cfg)

    out_file.write_text(contents)
    return out_file


@pytest.fixture
def device_package(config_file: Path) -> Path:
    """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() -> None:
    """Fixture to find required programs for pmbootstrap."""
    pmb.config.require_programs()


@pytest.fixture
def mock_devices_find_path(device_package: Path, monkeypatch: MonkeyPatch) -> None:
    """Fixture to mock pmb.helpers.devices.find_path()"""

    def mock_find_path(codename: str, file: str = "") -> Path | None:
        print(f"mock_find_path({codename}, {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: TempPathFactory) -> Path:
    """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: MonkeyPatch) -> None:
    """Common setup to mock cli.ask() to avoid reading from stdin"""
    import pmb.helpers.cli

    def mock_ask(
        question: str = "Continue?",
        choices: list[str] = ["y", "n"],
        default: str = "n",
        lowercase_answer: bool = True,
        validation_regex: None = None,
        complete: None = None,
    ) -> str:
        return default

    monkeypatch.setattr(pmb.helpers.cli, "ask", mock_ask)


# FIXME: get/set_context() is a bad hack :(
@pytest.fixture
def mock_context(monkeypatch: MonkeyPatch) -> None:
    """
    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: Context) -> None:
        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: Path, mock_context: None, logfile: Path) -> None:
    """
    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.ccache = True
    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() -> Arch:
    """Fixture to return the foreign arch."""
    if Arch.native() == Arch.x86_64:
        return Arch.aarch64

    return Arch.x86_64


@pytest.fixture
def pmaports(pmb_args: None, monkeypatch: MonkeyPatch) -> None:
    """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", "switch", "master"], working_dir=cfg.aports[-1]) == 0


@pytest.fixture
def tmp_file(tmp_path: Path) -> Path:
    return Path(tempfile.mkstemp(dir=tmp_path)[1])