"""Tests for CRIU checkpoint/restore functionality."""

import tempfile
from datetime import datetime
from pathlib import Path
from unittest.mock import MagicMock, patch

import pytest

from gaol.checkpoint.exceptions import (
    CheckpointError,
    CheckpointExecutionError,
    CheckpointImageError,
    CheckpointNotFoundError,
    ContainerNotFoundError,
    ContainerNotRunningError,
    CRIUKernelError,
    CRIUNotAvailableError,
    CRIUPermissionError,
    DockerExperimentalError,
    MigrationError,
    MigrationTargetError,
    PolicyNotFoundError,
    RestoreExecutionError,
    RetentionError,
    RuntimeNotSupportedError,
    VerificationError,
)
from gaol.checkpoint.models import (
    CheckpointHistory,
    CheckpointMetadata,
    CheckpointPolicy,
    CheckpointResult,
    CheckpointStatus,
    CheckpointType,
    CRIUCapabilities,
    DockerCheckpointCapabilities,
    MigrationResult,
    RestoreResult,
    RuntimeType,
)
from gaol.checkpoint.store import CheckpointStore


class TestCheckpointModels:
    """Tests for checkpoint Pydantic models."""

    def test_checkpoint_status_enum(self) -> None:
        """Test CheckpointStatus enum values."""
        assert CheckpointStatus.PENDING == "pending"
        assert CheckpointStatus.FREEZING == "freezing"
        assert CheckpointStatus.CHECKPOINTING == "checkpointing"
        assert CheckpointStatus.TRANSFERRING == "transferring"
        assert CheckpointStatus.RESTORING == "restoring"
        assert CheckpointStatus.COMPLETED == "completed"
        assert CheckpointStatus.FAILED == "failed"
        assert CheckpointStatus.CANCELLED == "cancelled"

    def test_checkpoint_type_enum(self) -> None:
        """Test CheckpointType enum values."""
        assert CheckpointType.FULL == "full"
        assert CheckpointType.MEMORY_ONLY == "memory_only"
        assert CheckpointType.ITERATIVE == "iterative"

    def test_runtime_type_enum(self) -> None:
        """Test RuntimeType enum values."""
        assert RuntimeType.DOCKER == "docker"
        assert RuntimeType.NSPAWN == "nspawn"

    def test_checkpoint_metadata_required_fields(self) -> None:
        """Test CheckpointMetadata with required fields."""
        now = datetime.now()
        meta = CheckpointMetadata(
            checkpoint_id="abc-123",
            container_name="test",
            checkpoint_name="before-upgrade",
            checkpoint_type=CheckpointType.FULL,
            created_at=now,
            image_dir="/tmp/checkpoints/test/before-upgrade",
            runtime=RuntimeType.DOCKER,
        )
        assert meta.checkpoint_id == "abc-123"
        assert meta.container_name == "test"
        assert meta.checkpoint_name == "before-upgrade"
        assert meta.checkpoint_type == CheckpointType.FULL
        assert meta.runtime == RuntimeType.DOCKER
        assert meta.container_was_running is True  # Default
        assert meta.verified is False  # Default

    def test_checkpoint_metadata_optional_fields(self) -> None:
        """Test CheckpointMetadata with optional fields."""
        now = datetime.now()
        meta = CheckpointMetadata(
            checkpoint_id="abc-123",
            container_name="test",
            checkpoint_name="checkpoint-1",
            checkpoint_type=CheckpointType.FULL,
            created_at=now,
            completed_at=now,
            size_bytes=1024 * 1024 * 100,  # 100 MB
            image_dir="/tmp/checkpoints/test/checkpoint-1",
            runtime=RuntimeType.NSPAWN,
            container_id="machine-123",
            pid_at_checkpoint=12345,
            checksum="sha256:abc123def456",
            verified=True,
            leave_running=True,
            tcp_established=True,
            external_unix_sockets=True,
        )
        assert meta.size_bytes == 1024 * 1024 * 100
        assert meta.container_id == "machine-123"
        assert meta.pid_at_checkpoint == 12345
        assert meta.checksum == "sha256:abc123def456"
        assert meta.verified is True
        assert meta.leave_running is True
        assert meta.tcp_established is True

    def test_checkpoint_result_defaults(self) -> None:
        """Test CheckpointResult default values."""
        result = CheckpointResult(
            container_name="test",
            checkpoint_name="test-checkpoint",
            checkpoint_id="abc-123",
        )
        assert result.container_name == "test"
        assert result.status == CheckpointStatus.PENDING
        assert result.checkpoint_type == CheckpointType.FULL
        assert result.size_bytes == 0
        assert result.error_message is None
        assert result.success is False  # Not completed yet

    def test_checkpoint_result_completed(self) -> None:
        """Test CheckpointResult when completed."""
        start = datetime.now()
        result = CheckpointResult(
            container_name="test",
            checkpoint_name="test-checkpoint",
            checkpoint_id="abc-123",
            started_at=start,
            completed_at=datetime.now(),
            status=CheckpointStatus.COMPLETED,
            size_bytes=50 * 1024 * 1024,
            image_dir="/tmp/checkpoints/test/test-checkpoint",
        )
        assert result.success is True
        assert result.duration_seconds is not None
        assert result.size_bytes == 50 * 1024 * 1024

    def test_checkpoint_result_failed(self) -> None:
        """Test CheckpointResult when failed."""
        result = CheckpointResult(
            container_name="test",
            checkpoint_name="test-checkpoint",
            checkpoint_id="abc-123",
            status=CheckpointStatus.FAILED,
            error_message="CRIU dump failed",
            error_output="Permission denied",
        )
        assert result.success is False
        assert result.error_message == "CRIU dump failed"
        assert result.error_output == "Permission denied"

    def test_restore_result_defaults(self) -> None:
        """Test RestoreResult default values."""
        result = RestoreResult(
            container_name="test",
            checkpoint_name="test-checkpoint",
            checkpoint_id="abc-123",
        )
        assert result.status == CheckpointStatus.PENDING
        assert result.new_container_id is None
        assert result.new_pid is None
        assert result.success is False

    def test_restore_result_completed(self) -> None:
        """Test RestoreResult when completed."""
        result = RestoreResult(
            container_name="test",
            checkpoint_name="test-checkpoint",
            checkpoint_id="abc-123",
            status=CheckpointStatus.COMPLETED,
            new_container_id="container-456",
            new_pid=67890,
        )
        assert result.success is True
        assert result.new_container_id == "container-456"
        assert result.new_pid == 67890

    def test_migration_result_defaults(self) -> None:
        """Test MigrationResult default values."""
        result = MigrationResult(
            container_name="test",
            source_host="host-a",
            target_host="host-b",
            checkpoint_name="migration-1",
            checkpoint_id="abc-123",
        )
        assert result.status == CheckpointStatus.PENDING
        assert result.checkpoint_size_bytes == 0
        assert result.transfer_size_bytes == 0
        assert result.success is False

    def test_checkpoint_policy_defaults(self) -> None:
        """Test CheckpointPolicy default values."""
        policy = CheckpointPolicy(container_name="test")
        assert policy.container_name == "test"
        assert policy.checkpoint_type == CheckpointType.FULL
        assert policy.leave_running is False
        assert policy.tcp_established is False
        assert policy.max_checkpoints == 10
        assert policy.max_age_days == 30
        assert policy.max_total_size_mb is None
        assert policy.verify_after_checkpoint is True

    def test_checkpoint_policy_custom(self) -> None:
        """Test CheckpointPolicy with custom values."""
        policy = CheckpointPolicy(
            container_name="mycontainer",
            checkpoint_type=CheckpointType.ITERATIVE,
            leave_running=True,
            tcp_established=True,
            max_checkpoints=5,
            max_age_days=7,
            max_total_size_mb=10240,
            pre_checkpoint_commands=["sync"],
            post_checkpoint_commands=["echo done"],
        )
        assert policy.container_name == "mycontainer"
        assert policy.checkpoint_type == CheckpointType.ITERATIVE
        assert policy.leave_running is True
        assert policy.tcp_established is True
        assert policy.max_checkpoints == 5
        assert policy.max_age_days == 7
        assert policy.max_total_size_mb == 10240

    def test_checkpoint_history_defaults(self) -> None:
        """Test CheckpointHistory default values."""
        history = CheckpointHistory(container_name="test")
        assert history.container_name == "test"
        assert history.checkpoints == []
        assert history.last_checkpoint is None
        assert history.total_checkpoints == 0
        assert history.successful_checkpoints == 0
        assert history.failed_checkpoints == 0
        assert history.total_size_bytes == 0

    def test_checkpoint_history_add_checkpoint(self) -> None:
        """Test adding checkpoints to history."""
        history = CheckpointHistory(container_name="test")
        now = datetime.now()

        meta = CheckpointMetadata(
            checkpoint_id="abc-123",
            container_name="test",
            checkpoint_name="checkpoint-1",
            checkpoint_type=CheckpointType.FULL,
            created_at=now,
            completed_at=now,
            size_bytes=50 * 1024 * 1024,
            image_dir="/tmp/test",
            runtime=RuntimeType.DOCKER,
        )

        history.add_checkpoint(meta)

        assert history.total_checkpoints == 1
        assert history.successful_checkpoints == 1
        assert history.failed_checkpoints == 0
        assert history.total_size_bytes == 50 * 1024 * 1024
        assert history.last_checkpoint == now
        assert len(history.checkpoints) == 1

    def test_checkpoint_history_remove_checkpoint(self) -> None:
        """Test removing checkpoints from history."""
        history = CheckpointHistory(container_name="test")
        now = datetime.now()

        meta = CheckpointMetadata(
            checkpoint_id="abc-123",
            container_name="test",
            checkpoint_name="checkpoint-1",
            checkpoint_type=CheckpointType.FULL,
            created_at=now,
            completed_at=now,
            size_bytes=50 * 1024 * 1024,
            image_dir="/tmp/test",
            runtime=RuntimeType.DOCKER,
        )

        history.add_checkpoint(meta)
        assert len(history.checkpoints) == 1

        result = history.remove_checkpoint("abc-123")
        assert result is True
        assert len(history.checkpoints) == 0
        assert history.total_size_bytes == 0

        # Try to remove non-existent checkpoint
        result = history.remove_checkpoint("xyz-789")
        assert result is False

    def test_checkpoint_history_get_checkpoint(self) -> None:
        """Test getting checkpoints from history."""
        history = CheckpointHistory(container_name="test")
        now = datetime.now()

        meta = CheckpointMetadata(
            checkpoint_id="abc-123",
            container_name="test",
            checkpoint_name="checkpoint-1",
            checkpoint_type=CheckpointType.FULL,
            created_at=now,
            completed_at=now,
            size_bytes=50 * 1024 * 1024,
            image_dir="/tmp/test",
            runtime=RuntimeType.DOCKER,
        )

        history.add_checkpoint(meta)

        # Get by name
        found = history.get_checkpoint("checkpoint-1")
        assert found is not None
        assert found.checkpoint_id == "abc-123"

        # Get by ID
        found_by_id = history.get_checkpoint_by_id("abc-123")
        assert found_by_id is not None
        assert found_by_id.checkpoint_name == "checkpoint-1"

        # Not found
        assert history.get_checkpoint("nonexistent") is None
        assert history.get_checkpoint_by_id("xyz-789") is None

    def test_criu_capabilities_defaults(self) -> None:
        """Test CRIUCapabilities default values."""
        caps = CRIUCapabilities()
        assert caps.available is False
        assert caps.version is None
        assert caps.kernel_checkpoint_restore is False
        assert caps.tcp_established is False
        assert caps.has_cap_sys_admin is False

    def test_criu_capabilities_available(self) -> None:
        """Test CRIUCapabilities when CRIU is available."""
        caps = CRIUCapabilities(
            available=True,
            version="3.18",
            kernel_checkpoint_restore=True,
            kernel_ns_last_pid=True,
            tcp_established=True,
            file_locks=True,
            has_cap_sys_admin=True,
            can_checkpoint_namespaces=True,
        )
        assert caps.available is True
        assert caps.version == "3.18"
        assert caps.tcp_established is True

    def test_docker_checkpoint_capabilities_defaults(self) -> None:
        """Test DockerCheckpointCapabilities default values."""
        caps = DockerCheckpointCapabilities()
        assert caps.available is False
        assert caps.experimental_enabled is False
        assert caps.checkpoint_supported is False
        assert caps.version is None

    def test_docker_checkpoint_capabilities_enabled(self) -> None:
        """Test DockerCheckpointCapabilities when enabled."""
        caps = DockerCheckpointCapabilities(
            available=True,
            experimental_enabled=True,
            checkpoint_supported=True,
            version="24.0.7",
        )
        assert caps.available is True
        assert caps.experimental_enabled is True
        assert caps.checkpoint_supported is True


class TestCheckpointExceptions:
    """Tests for checkpoint exceptions."""

    def test_checkpoint_error(self) -> None:
        """Test CheckpointError base exception."""
        err = CheckpointError("Something went wrong")
        assert str(err) == "Something went wrong"
        assert err.message == "Something went wrong"

    def test_container_not_found_error(self) -> None:
        """Test ContainerNotFoundError."""
        err = ContainerNotFoundError("mycontainer")
        assert err.container_name == "mycontainer"
        assert "mycontainer" in str(err)

    def test_container_not_running_error(self) -> None:
        """Test ContainerNotRunningError."""
        err = ContainerNotRunningError("mycontainer")
        assert err.container_name == "mycontainer"
        assert "not running" in str(err)

    def test_checkpoint_not_found_error(self) -> None:
        """Test CheckpointNotFoundError."""
        err = CheckpointNotFoundError("mycontainer", "checkpoint-1")
        assert err.container_name == "mycontainer"
        assert err.checkpoint_name == "checkpoint-1"
        assert "mycontainer" in str(err)
        assert "checkpoint-1" in str(err)

    def test_criu_not_available_error(self) -> None:
        """Test CRIUNotAvailableError."""
        err = CRIUNotAvailableError()
        assert "not available" in str(err)

        err_with_reason = CRIUNotAvailableError("binary not found")
        assert "binary not found" in str(err_with_reason)

    def test_criu_kernel_error(self) -> None:
        """Test CRIUKernelError."""
        err = CRIUKernelError("ns_last_pid")
        assert err.feature == "ns_last_pid"
        assert "ns_last_pid" in str(err)

    def test_criu_permission_error(self) -> None:
        """Test CRIUPermissionError."""
        err = CRIUPermissionError("checkpoint", "requires root")
        assert err.operation == "checkpoint"
        assert err.reason == "requires root"
        assert "checkpoint" in str(err)

    def test_docker_experimental_error(self) -> None:
        """Test DockerExperimentalError."""
        err = DockerExperimentalError()
        assert "experimental" in str(err).lower()
        assert "daemon.json" in str(err)

    def test_checkpoint_execution_error(self) -> None:
        """Test CheckpointExecutionError."""
        err = CheckpointExecutionError("CRIU dump failed", output="Error log")
        assert err.output == "Error log"
        assert "dump failed" in str(err)

    def test_restore_execution_error(self) -> None:
        """Test RestoreExecutionError."""
        err = RestoreExecutionError(
            "mycontainer", "checkpoint-1", "Image corrupt", output="Error log"
        )
        assert err.container_name == "mycontainer"
        assert err.checkpoint_name == "checkpoint-1"
        assert err.reason == "Image corrupt"
        assert err.output == "Error log"

    def test_migration_error(self) -> None:
        """Test MigrationError."""
        err = MigrationError("mycontainer", "target-host", "SSH failed")
        assert err.container_name == "mycontainer"
        assert err.target_host == "target-host"
        assert "SSH failed" in str(err)

    def test_migration_target_error(self) -> None:
        """Test MigrationTargetError."""
        err = MigrationTargetError("target-host", "CRIU not available")
        assert err.target_host == "target-host"
        assert "target-host" in str(err)

    def test_verification_error(self) -> None:
        """Test VerificationError."""
        err = VerificationError("checkpoint-1", "Checksum mismatch")
        assert err.checkpoint_name == "checkpoint-1"
        assert err.reason == "Checksum mismatch"

    def test_runtime_not_supported_error(self) -> None:
        """Test RuntimeNotSupportedError."""
        err = RuntimeNotSupportedError("podman")
        assert err.runtime == "podman"
        assert "podman" in str(err)

    def test_checkpoint_image_error(self) -> None:
        """Test CheckpointImageError."""
        err = CheckpointImageError("/tmp/images", "Corrupt file")
        assert err.image_dir == "/tmp/images"
        assert err.reason == "Corrupt file"


class TestCheckpointStore:
    """Tests for checkpoint store persistence."""

    def test_store_initialization(self, tmp_path: Path) -> None:
        """Test CheckpointStore initialization."""
        store = CheckpointStore(store_dir=tmp_path)
        assert store.images_dir == tmp_path / "images"

    def test_save_and_get_policy(self, tmp_path: Path) -> None:
        """Test saving and retrieving checkpoint policies."""
        store = CheckpointStore(store_dir=tmp_path)

        policy = CheckpointPolicy(
            container_name="test",
            leave_running=True,
            max_checkpoints=5,
        )
        store.save_policy(policy)

        retrieved = store.get_policy("test")
        assert retrieved is not None
        assert retrieved.container_name == "test"
        assert retrieved.leave_running is True
        assert retrieved.max_checkpoints == 5

    def test_delete_policy(self, tmp_path: Path) -> None:
        """Test deleting checkpoint policies."""
        store = CheckpointStore(store_dir=tmp_path)

        policy = CheckpointPolicy(container_name="test")
        store.save_policy(policy)
        assert store.policy_exists("test") is True

        store.delete_policy("test")
        assert store.policy_exists("test") is False

    def test_list_policies(self, tmp_path: Path) -> None:
        """Test listing all checkpoint policies."""
        store = CheckpointStore(store_dir=tmp_path)

        store.save_policy(CheckpointPolicy(container_name="test1"))
        store.save_policy(CheckpointPolicy(container_name="test2"))
        store.save_policy(CheckpointPolicy(container_name="test3"))

        policies = store.list_policies()
        assert len(policies) == 3
        names = [p.container_name for p in policies]
        assert "test1" in names
        assert "test2" in names
        assert "test3" in names

    def test_save_and_get_history(self, tmp_path: Path) -> None:
        """Test saving and retrieving checkpoint history."""
        store = CheckpointStore(store_dir=tmp_path)

        history = CheckpointHistory(
            container_name="test",
            total_checkpoints=5,
            successful_checkpoints=4,
            failed_checkpoints=1,
        )
        store.save_history(history)

        retrieved = store.get_history("test")
        assert retrieved.container_name == "test"
        assert retrieved.total_checkpoints == 5
        assert retrieved.successful_checkpoints == 4

    def test_get_history_creates_new(self, tmp_path: Path) -> None:
        """Test get_history creates new history if not exists."""
        store = CheckpointStore(store_dir=tmp_path)

        history = store.get_history("nonexistent")
        assert history.container_name == "nonexistent"
        assert history.total_checkpoints == 0

    def test_save_and_get_checkpoint_metadata(self, tmp_path: Path) -> None:
        """Test saving and retrieving checkpoint metadata."""
        store = CheckpointStore(store_dir=tmp_path)
        now = datetime.now()

        meta = CheckpointMetadata(
            checkpoint_id="abc-123",
            container_name="test",
            checkpoint_name="checkpoint-1",
            checkpoint_type=CheckpointType.FULL,
            created_at=now,
            image_dir="/tmp/test",
            runtime=RuntimeType.DOCKER,
        )
        store.save_checkpoint_metadata(meta)

        # Get by ID
        retrieved = store.get_checkpoint_metadata("test", "abc-123")
        assert retrieved is not None
        assert retrieved.checkpoint_id == "abc-123"
        assert retrieved.checkpoint_name == "checkpoint-1"

        # Get by name
        by_name = store.get_checkpoint_by_name("test", "checkpoint-1")
        assert by_name is not None
        assert by_name.checkpoint_id == "abc-123"

    def test_list_checkpoints(self, tmp_path: Path) -> None:
        """Test listing checkpoints for a container."""
        store = CheckpointStore(store_dir=tmp_path)
        now = datetime.now()

        for i in range(3):
            meta = CheckpointMetadata(
                checkpoint_id=f"id-{i}",
                container_name="test",
                checkpoint_name=f"checkpoint-{i}",
                checkpoint_type=CheckpointType.FULL,
                created_at=now,
                image_dir=f"/tmp/test-{i}",
                runtime=RuntimeType.DOCKER,
            )
            store.save_checkpoint_metadata(meta)

        checkpoints = store.list_checkpoints("test")
        assert len(checkpoints) == 3

    def test_delete_checkpoint_metadata(self, tmp_path: Path) -> None:
        """Test deleting checkpoint metadata."""
        store = CheckpointStore(store_dir=tmp_path)
        now = datetime.now()

        meta = CheckpointMetadata(
            checkpoint_id="abc-123",
            container_name="test",
            checkpoint_name="checkpoint-1",
            checkpoint_type=CheckpointType.FULL,
            created_at=now,
            image_dir="/tmp/test",
            runtime=RuntimeType.DOCKER,
        )
        store.save_checkpoint_metadata(meta)

        assert store.get_checkpoint_metadata("test", "abc-123") is not None

        deleted = store.delete_checkpoint_metadata("test", "abc-123")
        assert deleted is True
        assert store.get_checkpoint_metadata("test", "abc-123") is None

    def test_append_checkpoint(self, tmp_path: Path) -> None:
        """Test appending checkpoint to history."""
        store = CheckpointStore(store_dir=tmp_path)
        now = datetime.now()

        meta = CheckpointMetadata(
            checkpoint_id="abc-123",
            container_name="test",
            checkpoint_name="checkpoint-1",
            checkpoint_type=CheckpointType.FULL,
            created_at=now,
            completed_at=now,
            size_bytes=1024 * 1024,
            image_dir="/tmp/test",
            runtime=RuntimeType.DOCKER,
        )

        store.append_checkpoint(meta)

        # Check metadata saved
        saved = store.get_checkpoint_metadata("test", "abc-123")
        assert saved is not None

        # Check history updated
        history = store.get_history("test")
        assert history.total_checkpoints == 1
        assert history.successful_checkpoints == 1

    def test_image_dir_operations(self, tmp_path: Path) -> None:
        """Test image directory operations."""
        store = CheckpointStore(store_dir=tmp_path)

        # Create image dir
        image_dir = store.create_image_dir("test", "checkpoint-1")
        assert image_dir.exists()
        assert store.image_dir_exists("test", "checkpoint-1") is True

        # Create a file in the image dir
        test_file = image_dir / "core.img"
        test_file.write_bytes(b"x" * 1024)

        # Get size
        size = store.get_image_dir_size("test", "checkpoint-1")
        assert size == 1024

        # List image dirs
        store.create_image_dir("test", "checkpoint-2")
        dirs = store.list_image_dirs("test")
        assert len(dirs) == 2
        assert "checkpoint-1" in dirs
        assert "checkpoint-2" in dirs

        # Delete image dir
        deleted = store.delete_image_dir("test", "checkpoint-1")
        assert deleted is True
        assert store.image_dir_exists("test", "checkpoint-1") is False

    def test_delete_all_checkpoints(self, tmp_path: Path) -> None:
        """Test deleting all checkpoints for a container."""
        store = CheckpointStore(store_dir=tmp_path)
        now = datetime.now()

        # Create policy
        store.save_policy(CheckpointPolicy(container_name="test"))

        # Create checkpoint
        meta = CheckpointMetadata(
            checkpoint_id="abc-123",
            container_name="test",
            checkpoint_name="checkpoint-1",
            checkpoint_type=CheckpointType.FULL,
            created_at=now,
            image_dir="/tmp/test",
            runtime=RuntimeType.DOCKER,
        )
        store.append_checkpoint(meta)

        # Create image dir
        store.create_image_dir("test", "checkpoint-1")

        # Delete all
        deleted = store.delete_all_checkpoints("test")
        assert deleted is True

        # Verify everything is deleted
        assert store.policy_exists("test") is False
        assert store.get_checkpoint_metadata("test", "abc-123") is None
        assert store.image_dir_exists("test", "checkpoint-1") is False


class TestCheckpointExecutors:
    """Tests for checkpoint executors."""

    def test_criu_executor_availability_check(self) -> None:
        """Test CRIU executor availability check."""
        from gaol.checkpoint.executor import CRIUExecutor

        # This tests the static method - actual availability depends on system
        available = CRIUExecutor.is_available()
        # Result depends on whether CRIU is installed
        assert isinstance(available, bool)

    def test_criu_executor_get_version(self) -> None:
        """Test CRIU executor version check."""
        from gaol.checkpoint.executor import CRIUExecutor

        version = CRIUExecutor.get_version()
        # Result depends on whether CRIU is installed
        assert version is None or isinstance(version, str)

    def test_criu_executor_check_capabilities(self) -> None:
        """Test CRIU executor capability check."""
        from gaol.checkpoint.executor import CRIUExecutor

        caps = CRIUExecutor.check_capabilities()
        assert isinstance(caps, CRIUCapabilities)
        # Basic validation - if available, should have version
        if caps.available:
            assert caps.version is not None

    def test_docker_executor_availability_check(self) -> None:
        """Test Docker checkpoint executor availability check."""
        from gaol.checkpoint.executor import DockerCheckpointExecutor

        available = DockerCheckpointExecutor.is_available()
        assert isinstance(available, bool)

    def test_docker_executor_experimental_check(self) -> None:
        """Test Docker experimental mode check."""
        from gaol.checkpoint.executor import DockerCheckpointExecutor

        # Only check if Docker is available
        if DockerCheckpointExecutor.is_available():
            experimental = DockerCheckpointExecutor.is_experimental_enabled()
            assert isinstance(experimental, bool)

    def test_docker_executor_check_capabilities(self) -> None:
        """Test Docker executor capability check."""
        from gaol.checkpoint.executor import DockerCheckpointExecutor

        caps = DockerCheckpointExecutor.check_capabilities()
        assert isinstance(caps, DockerCheckpointCapabilities)

    def test_nspawn_executor_availability_check(self) -> None:
        """Test nspawn checkpoint executor availability check."""
        from gaol.checkpoint.executor import NspawnCheckpointExecutor

        available = NspawnCheckpointExecutor.is_available()
        assert isinstance(available, bool)


class TestCheckpointManager:
    """Tests for checkpoint manager."""

    def test_manager_check_criu(self) -> None:
        """Test manager CRIU capability check."""
        from gaol.checkpoint import get_checkpoint_manager

        with patch("gaol.checkpoint.manager.get_container_store") as mock_store:
            mock_store.return_value = MagicMock()
            manager = get_checkpoint_manager()

            caps = manager.check_criu()
            assert isinstance(caps, CRIUCapabilities)

    def test_manager_check_docker(self) -> None:
        """Test manager Docker capability check."""
        from gaol.checkpoint import get_checkpoint_manager

        with patch("gaol.checkpoint.manager.get_container_store") as mock_store:
            mock_store.return_value = MagicMock()
            manager = get_checkpoint_manager()

            caps = manager.check_docker()
            assert isinstance(caps, DockerCheckpointCapabilities)
