# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield
#
# SPDX-License-Identifier: MIT
"""
Pytest configuration and fixtures for vdkr, vpdmn and container-cross-install testing.

Usage:
    # Run all tests (default path: /tmp/vcontainer)
    pytest tests/ --vdkr-dir /tmp/vcontainer

    # Run vdkr tests only
    pytest tests/test_vdkr.py -v --vdkr-dir /tmp/vcontainer

    # Run vpdmn tests only
    pytest tests/test_vpdmn.py -v --vdkr-dir /tmp/vcontainer

    # Run with memres pre-started (faster)
    ./tests/memres-test.sh start --vdkr-dir /tmp/vcontainer
    pytest tests/test_vdkr.py --vdkr-dir /tmp/vcontainer --skip-destructive

    # Run specific test
    pytest tests/test_vdkr.py::TestMemresBasic -v --vdkr-dir /tmp/vcontainer

Requirements:
    pip install pytest

Environment:
    VDKR_STANDALONE_DIR: Path to extracted vdkr/vpdmn standalone tarball
    VDKR_ARCH: Architecture to test (x86_64 or aarch64), default: x86_64

Notes:
    - Tests use separate state directories (~/.vdkr-test/, ~/.vpdmn-test/) to avoid
      interfering with user's images in ~/.vdkr/ and ~/.vpdmn/.
    - If memres is already running, tests reuse it and don't stop it at the end.
    - Tests pull required images (alpine) automatically if not present.
"""

import os
import subprocess
import shutil
import tempfile
import signal
import atexit
import pytest
from pathlib import Path


# Test state directories - separate from user's ~/.vdkr/ and ~/.vpdmn/
TEST_STATE_BASE = os.path.expanduser("~/.vdkr-test")
VPDMN_TEST_STATE_BASE = os.path.expanduser("~/.vpdmn-test")

# Track test memres PIDs for cleanup
_test_memres_pids = set()


def _cleanup_test_memres():
    """
    Clean up any test memres processes that may have been left running.
    Called on exit (atexit) and signal handlers.
    """
    for state_base in [TEST_STATE_BASE, VPDMN_TEST_STATE_BASE]:
        for arch_dir in Path(state_base).glob("*"):
            pid_file = arch_dir / "daemon.pid"
            if pid_file.exists():
                try:
                    pid = int(pid_file.read_text().strip())
                    # Check if process is still running
                    if Path(f"/proc/{pid}").exists():
                        os.kill(pid, signal.SIGTERM)
                        # Give it a moment to clean up
                        import time
                        time.sleep(0.5)
                        # Force kill if still running
                        if Path(f"/proc/{pid}").exists():
                            os.kill(pid, signal.SIGKILL)
                except (ValueError, ProcessLookupError, PermissionError):
                    pass
                # Remove stale PID file
                try:
                    pid_file.unlink()
                except OSError:
                    pass


def _signal_handler(signum, frame):
    """Handle SIGINT/SIGTERM by cleaning up test memres before exit."""
    _cleanup_test_memres()
    # Re-raise the signal to trigger default behavior
    signal.signal(signum, signal.SIG_DFL)
    os.kill(os.getpid(), signum)


# Register cleanup handlers
atexit.register(_cleanup_test_memres)
signal.signal(signal.SIGINT, _signal_handler)
signal.signal(signal.SIGTERM, _signal_handler)


# Ports used by tests that need to be free
TEST_PORTS = [8080, 8081, 8082, 8888, 8001, 8002, 9999, 7777, 6666]


def _cleanup_orphan_qemu_on_ports():
    """
    Kill any QEMU processes holding ports used by tests.
    This handles cases where a previous test run or manual testing left
    orphan QEMU processes that would block test port bindings.
    """
    import re

    try:
        # Get listening sockets
        result = subprocess.run(
            ["ss", "-tlnp"],
            capture_output=True,
            text=True,
            timeout=5
        )
        if result.returncode != 0:
            return

        for line in result.stdout.splitlines():
            # Check if any test port is in use
            for port in TEST_PORTS:
                if f":{port}" in line and "qemu" in line.lower():
                    # Extract PID from ss output (format: users:(("qemu...",pid=12345,fd=...)))
                    match = re.search(r'pid=(\d+)', line)
                    if match:
                        pid = int(match.group(1))
                        try:
                            os.kill(pid, signal.SIGTERM)
                            import time
                            time.sleep(0.5)
                            # Force kill if still running
                            if Path(f"/proc/{pid}").exists():
                                os.kill(pid, signal.SIGKILL)
                        except (ProcessLookupError, PermissionError):
                            pass
                    break
    except (subprocess.TimeoutExpired, FileNotFoundError):
        pass


def pytest_addoption(parser):
    """Add custom command line options."""
    # vdkr/vpdmn options
    parser.addoption(
        "--vdkr-dir",
        action="store",
        default=os.environ.get("VDKR_STANDALONE_DIR", "/tmp/vcontainer"),
        help="Path to vcontainer standalone directory",
    )
    parser.addoption(
        "--arch",
        action="store",
        default=os.environ.get("VDKR_ARCH", "x86_64"),
        choices=["x86_64", "aarch64"],
        help="Target architecture to test",
    )
    parser.addoption(
        "--oci-image",
        action="store",
        default=os.environ.get("TEST_OCI_IMAGE"),
        help="Path to OCI image for import tests",
    )
    parser.addoption(
        "--skip-destructive",
        action="store_true",
        default=False,
        help="Skip tests that stop memres or clean state (useful when reusing test memres)",
    )
    # container-cross-install options
    parser.addoption(
        "--poky-dir",
        action="store",
        default=os.environ.get("POKY_DIR", "/opt/bruce/poky"),
        help="Path to poky directory",
    )
    parser.addoption(
        "--build-dir",
        action="store",
        default=os.environ.get("BUILD_DIR"),
        help="Path to build directory",
    )
    parser.addoption(
        "--machine",
        action="store",
        default=os.environ.get("MACHINE", "qemux86-64"),
        help="Target machine",
    )
    parser.addoption(
        "--image",
        action="store",
        default=os.environ.get("TEST_IMAGE", "container-image-host"),
        help="Image to boot for container verification tests",
    )
    parser.addoption(
        "--image-fstype",
        action="store",
        default=os.environ.get("TEST_IMAGE_FSTYPE", "ext4"),
        help="Image filesystem type (default: ext4)",
    )
    parser.addoption(
        "--boot-timeout",
        action="store",
        type=int,
        default=120,
        help="Timeout in seconds for image boot (default: 120)",
    )
    parser.addoption(
        "--no-kvm",
        action="store_true",
        default=False,
        help="Disable KVM acceleration",
    )
    parser.addoption(
        "--fail-stale",
        action="store_true",
        default=False,
        help="Fail if rootfs is stale (OCI containers or bbclass newer than rootfs)",
    )
    parser.addoption(
        "--max-age",
        action="store",
        type=float,
        default=24.0,
        help="Max rootfs age in hours before warning (default: 24)",
    )
    # Container registry options
    parser.addoption(
        "--registry-url",
        action="store",
        default=os.environ.get("TEST_REGISTRY_URL"),
        help="Registry URL for vdkr registry tests (e.g., 10.0.2.2:5000/yocto)",
    )
    parser.addoption(
        "--registry-script",
        action="store",
        default=os.environ.get("CONTAINER_REGISTRY_SCRIPT"),
        help="Path to container-registry.sh script",
    )
    parser.addoption(
        "--skip-registry-network",
        action="store_true",
        default=False,
        help="Skip registry tests that require network access to docker.io",
    )
    parser.addoption(
        "--secure-registry",
        action="store_true",
        default=False,
        help="Run secure registry tests (requires openssl, htpasswd)",
    )


def _cleanup_stale_test_state():
    """
    Clean up stale or corrupt test state directories.
    This ensures tests start with a clean slate if previous runs crashed.
    """
    for state_base in [TEST_STATE_BASE, VPDMN_TEST_STATE_BASE]:
        state_path = Path(state_base)
        if not state_path.exists():
            continue

        for arch_dir in state_path.glob("*"):
            if not arch_dir.is_dir():
                continue

            docker_state = arch_dir / "docker-state.img"
            daemon_pid = arch_dir / "daemon.pid"

            # Check if daemon is actually running
            daemon_running = False
            if daemon_pid.exists():
                try:
                    pid = int(daemon_pid.read_text().strip())
                    daemon_running = Path(f"/proc/{pid}").exists()
                except (ValueError, OSError):
                    pass

            # If daemon not running but state exists, it's stale - clean it
            if not daemon_running and docker_state.exists():
                # Check if docker-state.img needs journal recovery (corrupt)
                try:
                    result = subprocess.run(
                        ["file", str(docker_state)],
                        capture_output=True,
                        text=True,
                        timeout=5
                    )
                    if "needs journal recovery" in result.stdout:
                        # State is corrupt, clean it up
                        shutil.rmtree(arch_dir, ignore_errors=True)
                except (subprocess.TimeoutExpired, FileNotFoundError):
                    pass


@pytest.fixture(scope="session", autouse=True)
def cleanup_orphan_qemu():
    """Clean up orphan QEMU processes and stale test state at session start."""
    _cleanup_orphan_qemu_on_ports()
    _cleanup_stale_test_state()
    yield
    # Also clean up at end of session
    _cleanup_orphan_qemu_on_ports()


@pytest.fixture(scope="session")
def vdkr_dir(request):
    """Path to vdkr standalone directory."""
    path = Path(request.config.getoption("--vdkr-dir"))
    if not path.exists():
        pytest.skip(f"vdkr standalone directory not found: {path}")
    return path


@pytest.fixture(scope="session")
def arch(request):
    """Target architecture."""
    return request.config.getoption("--arch")


@pytest.fixture(scope="session")
def vdkr_bin(vdkr_dir, arch):
    """Path to vdkr binary for the target architecture.

    Tries arch-specific symlink first (vdkr-x86_64), then main vdkr binary.
    """
    # Try arch-specific symlink first
    binary = vdkr_dir / f"vdkr-{arch}"
    if binary.exists():
        return binary

    # Fall back to main vdkr binary
    binary = vdkr_dir / "vdkr"
    if binary.exists():
        return binary

    pytest.skip(f"vdkr binary not found: {vdkr_dir}/vdkr or {vdkr_dir}/vdkr-{arch}")


@pytest.fixture(scope="session")
def test_state_dir(arch):
    """Test-specific state directory to avoid interfering with user's state."""
    state_dir = Path(TEST_STATE_BASE) / arch
    state_dir.mkdir(parents=True, exist_ok=True)
    return state_dir


@pytest.fixture(scope="session")
def vdkr_env(vdkr_dir):
    """Environment variables for running vdkr."""
    env = os.environ.copy()

    # Source init-env.sh equivalent
    # Ensure vdkr_dir is a string for PATH concatenation
    vdkr_path = str(vdkr_dir)

    # Support both old layout (qemu/, lib/) and new SDK layout (sysroots/)
    sysroot_dir = vdkr_dir / "sysroots" / "x86_64-pokysdk-linux"
    if sysroot_dir.exists():
        # New SDK layout: sysroots/x86_64-pokysdk-linux/usr/bin/
        env["PATH"] = f"{vdkr_path}:{sysroot_dir}/usr/bin:/usr/bin:/bin:{env.get('PATH', '')}"
        # No LD_LIBRARY_PATH needed - SDK uses proper RPATH
    else:
        # Old layout: qemu/, lib/
        env["PATH"] = f"{vdkr_path}:{vdkr_path}/qemu:/usr/bin:/bin:{env.get('PATH', '')}"
        env["LD_LIBRARY_PATH"] = f"{vdkr_path}/lib:{env.get('LD_LIBRARY_PATH', '')}"

    return env


@pytest.fixture(scope="session")
def oci_image(request):
    """Path to test OCI image, if available."""
    path = request.config.getoption("--oci-image")
    if path:
        path = Path(path)
        if not path.exists():
            pytest.skip(f"OCI image not found: {path}")
        return path
    return None


class VdkrRunner:
    """Helper class for running vdkr commands."""

    def __init__(self, binary: Path, env: dict, arch: str, state_dir: Path):
        self.binary = binary
        self.env = env
        self.arch = arch
        self.state_dir = state_dir
        self._user_memres_was_running = None
        # Check if we're using main vdkr (needs --arch) vs arch-specific symlink
        self._needs_arch_flag = binary.name == "vdkr"

    def run(self, *args, timeout=120, check=True, capture_output=True):
        """Run a vdkr command with test state directory."""
        cmd = [str(self.binary)]
        if self._needs_arch_flag:
            cmd.extend(["--arch", self.arch])
        cmd.extend(["--state-dir", str(self.state_dir)])
        cmd.extend(list(args))
        result = subprocess.run(
            cmd,
            env=self.env,
            timeout=timeout,
            check=False,  # Don't raise immediately, check manually for better error messages
            capture_output=capture_output,
            text=True,
        )
        if check and result.returncode != 0:
            error_msg = f"Command failed: {' '.join(cmd)}\n"
            error_msg += f"Exit code: {result.returncode}\n"
            if result.stdout:
                error_msg += f"stdout: {result.stdout}\n"
            if result.stderr:
                error_msg += f"stderr: {result.stderr}\n"
            # Print error so it's visible in test output
            print(error_msg)
            raise AssertionError(error_msg)
        return result

    def memres_start(self, timeout=120, port_forwards=None, no_registry=False):
        """Start memory resident mode.

        Args:
            timeout: Command timeout in seconds
            port_forwards: List of port forwards, e.g., ["8080:80", "2222:22"]
            no_registry: Disable baked-in registry (default False - registry check is now smart)
        """
        args = ["memres", "start"]
        if no_registry:
            args.append("--no-registry")
        if port_forwards:
            for pf in port_forwards:
                args.extend(["-p", pf])
        return self.run(*args, timeout=timeout)

    def memres_stop(self, timeout=30):
        """Stop memory resident mode."""
        return self.run("memres", "stop", timeout=timeout, check=False)

    def memres_status(self):
        """Check memory resident status."""
        return self.run("memres", "status", check=False)

    def is_memres_running(self):
        """Check if memres is running (in test state dir)."""
        result = self.memres_status()
        return result.returncode == 0 and "running" in result.stdout.lower()

    def ensure_memres(self, timeout=180):
        """Ensure memres is running, starting it if needed."""
        if not self.is_memres_running():
            result = self.memres_start(timeout=timeout)
            if result.returncode != 0:
                raise RuntimeError(f"Failed to start memres: {result.stderr}")

    def is_user_memres_running(self):
        """Check if user's memres is running (in default ~/.vdkr/)."""
        # Check without --state-dir to see user's memres
        cmd = [str(self.binary)]
        if self._needs_arch_flag:
            cmd.extend(["--arch", self.arch])
        cmd.extend(["memres", "status"])
        result = subprocess.run(
            cmd, env=self.env, capture_output=True, text=True, timeout=10
        )
        return result.returncode == 0 and "running" in result.stdout.lower()

    def images(self, timeout=120):
        """List images."""
        return self.run("images", timeout=timeout)

    def clean(self):
        """Clean state."""
        return self.run("clean", check=False)

    def vimport(self, path, name, timeout=120):
        """Import an OCI image."""
        return self.run("vimport", str(path), name, timeout=timeout)

    def pull(self, image, timeout=180):
        """Pull an image from registry."""
        return self.run("pull", image, timeout=timeout)

    def rmi(self, image, timeout=60):
        """Remove an image."""
        return self.run("rmi", image, timeout=timeout, check=False)

    def vrun(self, image, *cmd, timeout=120):
        """Run a command in a container."""
        return self.run("vrun", image, *cmd, timeout=timeout)

    def inspect(self, target, timeout=60):
        """Inspect an image or container."""
        return self.run("inspect", target, timeout=timeout)

    def save(self, output_file, image, timeout=120):
        """Save an image to a tar file."""
        return self.run("save", "-o", str(output_file), image, timeout=timeout)

    def load(self, input_file, timeout=120):
        """Load an image from a tar file."""
        return self.run("load", "-i", str(input_file), timeout=timeout)

    def has_image(self, image_name):
        """Check if an image exists.

        Uses 'image inspect' for precise matching instead of substring
        search in 'images' output, which can give false positives
        (e.g., 'nginx:alpine' matching search for 'alpine').
        """
        self.ensure_memres()
        # Use image inspect for precise matching - returns 0 if image exists
        ref = image_name if ":" in image_name else f"{image_name}:latest"
        result = self.run("image", "inspect", ref, check=False, capture_output=True)
        return result.returncode == 0

    def ensure_alpine(self, timeout=300):
        """Ensure alpine:latest is available, pulling if necessary."""
        # Ensure memres is running first (in case a previous test stopped it)
        self.ensure_memres()
        if not self.has_image("alpine"):
            self.pull("alpine:latest", timeout=timeout)

    def ensure_busybox(self, timeout=300):
        """Ensure busybox:latest is available, pulling if necessary."""
        # Ensure memres is running first (in case a previous test stopped it)
        self.ensure_memres()
        if not self.has_image("busybox"):
            self.pull("busybox:latest", timeout=timeout)


@pytest.fixture(scope="session")
def vdkr(vdkr_bin, vdkr_env, arch, test_state_dir):
    """VdkrRunner instance for running vdkr commands."""
    return VdkrRunner(vdkr_bin, vdkr_env, arch, test_state_dir)


@pytest.fixture(scope="session")
def memres_session(vdkr):
    """
    Session-scoped fixture that ensures memres is running for tests.
    Uses separate test state directory (~/.vdkr-test/).

    Note: TestMemresBasic tests may stop/restart memres during the session.
    Tests using this fixture should call ensure_memres() or ensure_alpine()
    to guarantee memres is running before executing commands.
    """
    # Check if memres was already running at session start
    was_running_at_start = vdkr.is_memres_running()

    # Ensure memres is running
    vdkr.ensure_memres()

    yield vdkr

    # Only stop memres if it wasn't running when we started
    if not was_running_at_start:
        vdkr.memres_stop()


@pytest.fixture
def temp_dir():
    """Create a temporary directory for test files."""
    tmpdir = tempfile.mkdtemp(prefix="vdkr-test-")
    yield Path(tmpdir)
    shutil.rmtree(tmpdir, ignore_errors=True)


# Markers
def pytest_configure(config):
    """Register custom markers."""
    config.addinivalue_line(
        "markers", "slow: marks tests as slow (deselect with '-m \"not slow\"')"
    )
    config.addinivalue_line(
        "markers", "memres: marks tests that require memory resident mode"
    )
    config.addinivalue_line(
        "markers", "network: marks tests that require network access"
    )
    config.addinivalue_line(
        "markers", "secure: marks tests that require secure registry mode (TLS/auth)"
    )
    config.addinivalue_line(
        "markers", "boot: marks tests that boot a QEMU image (requires built image)"
    )


@pytest.fixture
def skip_secure(request):
    """Skip if secure registry tests not enabled.

    Use with tests that require secure registry infrastructure:
    - openssl for certificate generation
    - htpasswd for authentication setup
    - CONTAINER_REGISTRY_SECURE=1 baked into script

    Enable with: pytest --secure-registry
    """
    if not request.config.getoption("--secure-registry"):
        pytest.skip("Secure registry tests not enabled (use --secure-registry)")
    return False


# ============================================================================
# vpdmn (Podman) fixtures
# ============================================================================

@pytest.fixture(scope="session")
def vpdmn_bin(vdkr_dir, arch):
    """Path to vpdmn binary for the target architecture.

    Tries arch-specific symlink first (vpdmn-x86_64), then main vpdmn binary.
    """
    # Try arch-specific symlink first
    binary = vdkr_dir / f"vpdmn-{arch}"
    if binary.exists():
        return binary

    # Fall back to main vpdmn binary
    binary = vdkr_dir / "vpdmn"
    if binary.exists():
        return binary

    pytest.skip(f"vpdmn binary not found: {vdkr_dir}/vpdmn or {vdkr_dir}/vpdmn-{arch}")


@pytest.fixture(scope="session")
def vpdmn_test_state_dir(arch):
    """Test-specific state directory for vpdmn to avoid interfering with user's state."""
    state_dir = Path(VPDMN_TEST_STATE_BASE) / arch
    state_dir.mkdir(parents=True, exist_ok=True)
    return state_dir


class VpdmnRunner:
    """Helper class for running vpdmn commands."""

    def __init__(self, binary: Path, env: dict, arch: str, state_dir: Path):
        self.binary = binary
        self.env = env
        self.arch = arch
        self.state_dir = state_dir
        self._user_memres_was_running = None
        # Check if we're using main vpdmn (needs --arch) vs arch-specific symlink
        self._needs_arch_flag = binary.name == "vpdmn"

    def run(self, *args, timeout=120, check=True, capture_output=True):
        """Run a vpdmn command with test state directory."""
        cmd = [str(self.binary)]
        if self._needs_arch_flag:
            cmd.extend(["--arch", self.arch])
        cmd.extend(["--state-dir", str(self.state_dir)])
        cmd.extend(list(args))
        result = subprocess.run(
            cmd,
            env=self.env,
            timeout=timeout,
            check=False,  # Don't raise immediately, check manually for better error messages
            capture_output=capture_output,
            text=True,
        )
        if check and result.returncode != 0:
            error_msg = f"Command failed: {' '.join(cmd)}\n"
            error_msg += f"Exit code: {result.returncode}\n"
            if result.stdout:
                error_msg += f"stdout: {result.stdout}\n"
            if result.stderr:
                error_msg += f"stderr: {result.stderr}\n"
            # Print error so it's visible in test output
            print(error_msg)
            raise AssertionError(error_msg)
        return result

    def memres_start(self, timeout=120, port_forwards=None, no_registry=False):
        """Start memory resident mode.

        Args:
            timeout: Command timeout in seconds
            port_forwards: List of port forwards, e.g., ["8080:80", "2222:22"]
            no_registry: Disable baked-in registry (default False - registry check is now smart)
        """
        args = ["memres", "start"]
        if no_registry:
            args.append("--no-registry")
        if port_forwards:
            for pf in port_forwards:
                args.extend(["-p", pf])
        return self.run(*args, timeout=timeout)

    def memres_stop(self, timeout=30):
        """Stop memory resident mode."""
        return self.run("memres", "stop", timeout=timeout, check=False)

    def memres_status(self):
        """Check memory resident status."""
        return self.run("memres", "status", check=False)

    def is_memres_running(self):
        """Check if memres is running (in test state dir)."""
        result = self.memres_status()
        return result.returncode == 0 and "running" in result.stdout.lower()

    def ensure_memres(self, timeout=180):
        """Ensure memres is running, starting it if needed."""
        if not self.is_memres_running():
            result = self.memres_start(timeout=timeout)
            if result.returncode != 0:
                raise RuntimeError(f"Failed to start memres: {result.stderr}")

    def images(self, timeout=120):
        """List images."""
        return self.run("images", timeout=timeout)

    def clean(self):
        """Clean state."""
        return self.run("clean", check=False)

    def vimport(self, path, name, timeout=120):
        """Import an OCI image."""
        return self.run("vimport", str(path), name, timeout=timeout)

    def pull(self, image, timeout=180):
        """Pull an image from registry."""
        return self.run("pull", image, timeout=timeout)

    def rmi(self, image, timeout=60):
        """Remove an image."""
        return self.run("rmi", image, timeout=timeout, check=False)

    def vrun(self, image, *cmd, timeout=120):
        """Run a command in a container."""
        return self.run("vrun", image, *cmd, timeout=timeout)

    def inspect(self, target, timeout=60):
        """Inspect an image or container."""
        return self.run("inspect", target, timeout=timeout)

    def save(self, output_file, image, timeout=120):
        """Save an image to a tar file."""
        return self.run("save", "-o", str(output_file), image, timeout=timeout)

    def load(self, input_file, timeout=120):
        """Load an image from a tar file."""
        return self.run("load", "-i", str(input_file), timeout=timeout)

    def has_image(self, image_name):
        """Check if an image exists.

        Uses 'image inspect' for precise matching instead of substring
        search in 'images' output, which can give false positives
        (e.g., 'nginx:alpine' matching search for 'alpine').
        """
        self.ensure_memres()
        # Use image inspect for precise matching - returns 0 if image exists
        ref = image_name if ":" in image_name else f"{image_name}:latest"
        result = self.run("image", "inspect", ref, check=False, capture_output=True)
        return result.returncode == 0

    def ensure_alpine(self, timeout=300):
        """Ensure alpine:latest is available, pulling if necessary."""
        # Ensure memres is running first (in case a previous test stopped it)
        self.ensure_memres()
        if not self.has_image("alpine"):
            self.pull("alpine:latest", timeout=timeout)

    def ensure_busybox(self, timeout=300):
        """Ensure busybox:latest is available, pulling if necessary."""
        # Ensure memres is running first (in case a previous test stopped it)
        self.ensure_memres()
        if not self.has_image("busybox"):
            self.pull("busybox:latest", timeout=timeout)


@pytest.fixture(scope="session")
def vpdmn(vpdmn_bin, vdkr_env, arch, vpdmn_test_state_dir):
    """VpdmnRunner instance for running vpdmn commands."""
    return VpdmnRunner(vpdmn_bin, vdkr_env, arch, vpdmn_test_state_dir)


@pytest.fixture(scope="session")
def vpdmn_memres_session(vpdmn):
    """
    Session-scoped fixture that ensures memres is running for vpdmn tests.
    Uses separate test state directory (~/.vpdmn-test/).

    Note: TestMemresBasic tests may stop/restart memres during the session.
    Tests using this fixture should call ensure_memres() or ensure_alpine()
    to guarantee memres is running before executing commands.
    """
    # Check if memres was already running at session start
    was_running_at_start = vpdmn.is_memres_running()

    # Ensure memres is running
    vpdmn.ensure_memres()

    yield vpdmn

    # Only stop memres if it wasn't running when we started
    if not was_running_at_start:
        vpdmn.memres_stop()
