summaryrefslogtreecommitdiffstats
path: root/test/conftest.py
blob: a1e48936fd84f3e83fb06b29d7f72ffbb106c58e (plain)
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
"""Pytest fixtures."""
import importlib.metadata
import json
import pathlib
import subprocess
import sys
from collections.abc import Generator
from pathlib import Path
from typing import Callable

import pytest

from ansible_compat.runtime import Runtime


@pytest.fixture()
# pylint: disable=unused-argument
def runtime(scope: str = "session") -> Generator[Runtime, None, None]:  # noqa: ARG001
    """Isolated runtime fixture."""
    instance = Runtime(isolated=True)
    yield instance
    instance.clean()


@pytest.fixture()
# pylint: disable=unused-argument
def runtime_tmp(
    tmp_path: pathlib.Path,
    scope: str = "session",  # noqa: ARG001
) -> Generator[Runtime, None, None]:
    """Isolated runtime fixture using a temp directory."""
    instance = Runtime(project_dir=tmp_path, isolated=True)
    yield instance
    instance.clean()


def query_pkg_version(pkg: str) -> str:
    """Get the version of a current installed package.

    :param pkg: Package name
    :return: Package version
    """
    return importlib.metadata.version(pkg)


@pytest.fixture()
def pkg_version() -> Callable[[str], str]:
    """Get the version of a current installed package.

    :return: Callable function to get package version
    """
    return query_pkg_version


class VirtualEnvironment:
    """Virtualenv wrapper."""

    def __init__(self, path: Path) -> None:
        """Initialize.

        :param path: Path to virtualenv
        """
        self.project = path
        self.venv_path = self.project / "venv"
        self.venv_bin_path = self.venv_path / "bin"
        self.venv_python_path = self.venv_bin_path / "python"

    def create(self) -> None:
        """Create virtualenv."""
        cmd = [str(sys.executable), "-m", "venv", str(self.venv_path)]
        subprocess.check_call(args=cmd)
        # Install this package into the virtual environment
        self.install(f"{__file__}/../..")

    def install(self, *packages: str) -> None:
        """Install packages in virtualenv.

        :param packages: Packages to install
        """
        cmd = [str(self.venv_python_path), "-m", "pip", "install", *packages]
        subprocess.check_call(args=cmd)

    def python_script_run(self, script: str) -> subprocess.CompletedProcess[str]:
        """Run command in project dir using venv.

        :param args: Command to run
        """
        proc = subprocess.run(
            args=[self.venv_python_path, "-c", script],
            capture_output=True,
            cwd=self.project,
            check=False,
            text=True,
        )
        return proc

    def site_package_dirs(self) -> list[Path]:
        """Get site packages.

        :return: List of site packages dirs
        """
        script = "import json, site; print(json.dumps(site.getsitepackages()))"
        proc = subprocess.run(
            args=[self.venv_python_path, "-c", script],
            capture_output=True,
            check=False,
            text=True,
        )
        dirs = json.loads(proc.stdout)
        if not isinstance(dirs, list):
            msg = "Expected list of site packages"
            raise TypeError(msg)
        sanitized = list({Path(d).resolve() for d in dirs})
        return sanitized


@pytest.fixture(scope="module")
def venv_module(tmp_path_factory: pytest.TempPathFactory) -> VirtualEnvironment:
    """Create a virtualenv in a temporary directory.

    :param tmp_path: pytest fixture for temp path
    :return: VirtualEnvironment instance
    """
    test_project = tmp_path_factory.mktemp(basename="test_project-", numbered=True)
    _venv = VirtualEnvironment(test_project)
    _venv.create()
    return _venv