Skip to content

Commit

Permalink
Remove _OciRuntimeBase class and integrate this into OciRuntimeABC
Browse files Browse the repository at this point in the history
  • Loading branch information
dcermak committed Jan 10, 2025
1 parent 3164ec0 commit 3926a84
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 56 deletions.
83 changes: 27 additions & 56 deletions pytest_container/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from abc import ABC
from abc import abstractmethod
from dataclasses import dataclass
from dataclasses import field
from os import getenv
from pathlib import Path
from subprocess import check_output
Expand Down Expand Up @@ -157,7 +156,7 @@ def __generate_cmp(
) -> Callable[["Version", Any], bool]:
def cmp(self: Version, other: Any) -> bool:
if not isinstance(other, Version):
return NotImplemented
return NotImplemented # type: ignore

if self.major == other.major:
if self.minor == other.minor:
Expand All @@ -180,25 +179,28 @@ def __gt__(self, other: Any) -> bool:
return Version.__generate_cmp(lambda m, n: m > n)(self, other)


@dataclass(frozen=True)
class _OciRuntimeBase:
#: command that builds the Dockerfile in the current working directory
build_command: List[str] = field(default_factory=list)
#: the "main" binary of this runtime, e.g. podman or docker
runner_binary: str = ""
_runtime_functional: bool = False


class OciRuntimeABC(ABC):
"""The abstract base class defining the interface of a container runtime."""

@staticmethod
@abstractmethod
def _runtime_error_message() -> str:
"""Returns a human readable error message why the runtime does not
function.
def __init__(self, build_command: List[str], runner_binary: str) -> None:
#: command that builds the Dockerfile in the current working directory
self._build_command = build_command

#: the "main" binary of this runtime, e.g. podman or docker
self._runner_binary: str = runner_binary

@property
def build_command(self) -> List[str]:
"""Command that builds the :file:`Dockerfile` in the current working
directory.
"""
return self._build_command

@property
def runner_binary(self) -> str:
"""The "main" binary of this runtime, e.g. podman or docker."""
return self._runner_binary

def get_container_health(self, container_id: str) -> ContainerHealth:
"""Inspects the running container with the supplied id and returns its current
Expand Down Expand Up @@ -229,21 +231,9 @@ def supports_healthcheck_inherit_from_base(self) -> bool:
"""


class OciRuntimeBase(_OciRuntimeBase, OciRuntimeABC, ToParamMixin):
class OciRuntimeBase(OciRuntimeABC, ToParamMixin):
"""Base class of the Container Runtimes."""

def __post_init__(self) -> None:
if not self.build_command or not self.runner_binary:
raise ValueError(
f"build_command ({self.build_command}) or runner_binary "
f"({self.runner_binary}) were not specified"
)
if not self._runtime_functional:
raise RuntimeError(
f"The runtime {self.__class__.__name__} is not functional: "
+ self._runtime_error_message()
)

@staticmethod
def get_image_id_from_iidfile(iidfile_path: str) -> str:
"""Returns the image id/hash from the iidfile that has been created by
Expand Down Expand Up @@ -434,7 +424,7 @@ def _get_podman_version(version_stdout: str) -> Version:


def _get_buildah_version() -> Version:
version_stdout = LOCALHOST.run_expect([0], "buildah --version").stdout
version_stdout = LOCALHOST.check_output("buildah --version")
build_version_begin = "buildah version "
if not version_stdout.startswith(build_version_begin):
raise RuntimeError(
Expand All @@ -452,29 +442,19 @@ class PodmanRuntime(OciRuntimeBase):
"""

_runtime_functional = LOCALHOST.run("podman ps").succeeded
_buildah_functional = LOCALHOST.run("buildah").succeeded

@staticmethod
def _runtime_error_message() -> str:
if PodmanRuntime._runtime_functional:
return ""

def __init__(self) -> None:
podman_ps = LOCALHOST.run("podman ps")
assert not podman_ps.succeeded, (
"podman runtime is not functional, but 'podman ps' succeeded"
)
return str(podman_ps.stderr)
if not podman_ps.succeeded:
raise RuntimeError(f"`podman ps` failed with {podman_ps.stderr}")

Check warning on line 448 in pytest_container/runtime.py

View check run for this annotation

Codecov / codecov/patch

pytest_container/runtime.py#L448

Added line #L448 was not covered by tests

def __init__(self) -> None:
self._buildah_functional = LOCALHOST.run("buildah").succeeded
super().__init__(
build_command=(
["buildah", "bud", "--layers", "--force-rm"]
if self._buildah_functional
else ["podman", "build", "--layers", "--force-rm"]
),
runner_binary="podman",
_runtime_functional=self._runtime_functional,
)

# pragma pylint: disable=used-before-assignment
Expand Down Expand Up @@ -558,23 +538,14 @@ class DockerRuntime(OciRuntimeBase):
"""The container runtime using :command:`docker` for building and running
containers."""

_runtime_functional = LOCALHOST.run("docker ps").succeeded

@staticmethod
def _runtime_error_message() -> str:
if DockerRuntime._runtime_functional:
return ""
def __init__(self) -> None:
docker_ps = LOCALHOST.run("docker ps")
assert not docker_ps.succeeded, (
"docker runtime is not functional, but 'docker ps' succeeded"
)
return str(docker_ps.stderr)
if not docker_ps.succeeded:
raise RuntimeError(f"`docker ps` failed with {docker_ps.stderr}")

Check warning on line 544 in pytest_container/runtime.py

View check run for this annotation

Codecov / codecov/patch

pytest_container/runtime.py#L544

Added line #L544 was not covered by tests

def __init__(self) -> None:
super().__init__(
build_command=["docker", "build", "--force-rm"],
runner_binary="docker",
_runtime_functional=self._runtime_functional,
)

@cached_property
Expand Down
16 changes: 16 additions & 0 deletions tests/test_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import pytest

from pytest_container.runtime import LOCALHOST
from pytest_container.runtime import DockerRuntime
from pytest_container.runtime import OciRuntimeBase
from pytest_container.runtime import PodmanRuntime
Expand Down Expand Up @@ -36,7 +37,22 @@ def test_runtime_selection(
# pylint: disable-next=redefined-outer-name,unused-argument
container_runtime_envvar: None,
runtime: OciRuntimeBase,
monkeypatch: pytest.MonkeyPatch,
):
class Succeeded:
@property
def succeeded(self) -> bool:
return True

@property
def rc(self) -> int:
return 0

def mock_run(*args, **kwargs):
return Succeeded()

monkeypatch.setattr(LOCALHOST, "run", mock_run)

assert get_selected_runtime() == runtime


Expand Down

0 comments on commit 3926a84

Please sign in to comment.