Skip to content

Commit

Permalink
feat: make pytest-testinfra optional
Browse files Browse the repository at this point in the history
This removes the use of testinfra from the main codebase and the test suite
making it an optional dependency.

You can still use "connection.connection" to get testinfra's connection object
if you have it installed.
  • Loading branch information
lqc committed Oct 18, 2024
1 parent 1e19e12 commit e3afa55
Show file tree
Hide file tree
Showing 27 changed files with 787 additions and 507 deletions.
23 changes: 15 additions & 8 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ Find the latest documentation on `dcermak.github.io/pytest_container
<https://dcermak.github.io/pytest_container/>`_.

``pytest_container`` is a `pytest <https://pytest.org>`_ plugin
to test container images via pytest fixtures and `testinfra
<https://testinfra.readthedocs.io/en/latest/>`_. It takes care of all the boring
to test container images via pytest fixtures. It takes care of all the boring
tasks, like spinning up containers, finding free ports and cleaning up after
tests, and allows you to focus on implementing the actual tests.

Expand All @@ -49,16 +48,24 @@ instantiating a ``Container`` and parametrizing a test function with the
@pytest.mark.parametrize("container", [TW], indirect=["container"])
def test_etc_os_release_present(container: ContainerData):
assert container.connection.file("/etc/os-release").exists
assert container.remote.check_output("test -f /etc/os-release")
The fixture automatically pulls and spins up the container, stops it and removes
it after the test is completed. Your test function receives an instance of
``ContainerData`` with the ``ContainerData.connection`` attribute. The
``ContainerData.connection`` attribute is a `testinfra
<https://testinfra.readthedocs.io/en/latest/>`_ connection object. It can be
used to run basic tests inside the container itself. For example, you can check
whether files are present, packages are installed, etc.
``ContainerData``.


Testinfa
--------

You can optionally use the `testinfra <https://testinfra.readthedocs.io/en/latest/>`_
library to interact with the container. You need to install the ``pytest-testinfra``
package directly or use the ``[testinfra]`` extra on this package.

If test infra is installed, the ``ContainerData`` instance will have a
``connection`` attribute that is an instance of ``testinfra.Connection``. Otherwise
this attribute will be ``None``.


Use cases
Expand Down
22 changes: 18 additions & 4 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 12 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,22 @@ classifiers = [
[tool.poetry.dependencies]
python = ">=3.6.2,<4.0"
pytest = ">= 3.10"
pytest-testinfra = [
{ version = ">=6.4.0", python = "< 3.7" },
{ version = ">=7.0", python = ">= 3.7,< 3.8" },
{ version = ">=8.0", python = ">= 3.8" }
]
dataclasses = { version = ">=0.8", python = "< 3.7" }
typing-extensions = { version = ">=3.0", markers="python_version < '3.8'" }
cached-property = { version = "^1.5", markers="python_version < '3.8'" }
filelock = "^3.4"
deprecation = "^2.1"

pytest-testinfra = [
{ version = ">=6.4.0", python = "< 3.7", optional = true },
{ version = ">=7.0", python = ">= 3.7,< 3.8", optional = true },
{ version = ">=8.0", python = ">= 3.8", optional = true }
]


[tool.poetry.extras]
testinfra = ["pytest-testinfra"]

[tool.poetry.dev-dependencies]
black = ">=21.9b0"
mypy = ">=0.942"
Expand All @@ -51,6 +56,8 @@ pytest-xdist = ">=2.4.0"
Sphinx = ">=5.0"
pytest-rerunfailures = ">=10.2"
typeguard = ">=2.13"
ifaddr = "^0.2.0"


[build-system]
requires = ["poetry-core>=1.0.0"]
Expand Down
31 changes: 18 additions & 13 deletions pytest_container/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
builds via :py:class:`MultiStageBuild`.
"""
import subprocess
import tempfile
from dataclasses import dataclass
from os.path import basename
from os.path import join
from pathlib import Path
from string import Template
from subprocess import check_output
from typing import Dict
from typing import List
from typing import Optional
Expand Down Expand Up @@ -156,10 +156,12 @@ def containerfile(self) -> str:
"""
return Template(self.containerfile_template).substitute(
**{
k: v
if isinstance(v, str)
else str(
container_and_marks_from_pytest_param(v)[0]._build_tag
k: (
v
if isinstance(v, str)
else str(
container_and_marks_from_pytest_param(v)[0]._build_tag
)
)
for k, v in self.containers.items()
}
Expand Down Expand Up @@ -222,15 +224,18 @@ def run_build_step(
# This is an ugly, duplication of the launcher code
with tempfile.TemporaryDirectory() as tmp_dir:
iidfile = join(tmp_dir, str(uuid4()))
cmd = (
runtime.build_command
+ (extra_build_args or [])
+ [f"--iidfile={iidfile}"]
+ (["--target", target] if target else [])
+ [str(tmp_path)]
)
cmd: List[str] = []
cmd.extend(runtime.build_command)
if extra_build_args:
cmd.extend(extra_build_args)
cmd.extend(["--iidfile", iidfile])
if target:
cmd.extend(["--target", target])
cmd.append(str(tmp_path))
_logger.debug("Running multistage container build: %s", cmd)
check_output(cmd)
subprocess.check_call(
cmd, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE
)
return runtime.get_image_id_from_iidfile(iidfile)

def build(
Expand Down
15 changes: 15 additions & 0 deletions pytest_container/compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from typing import TYPE_CHECKING

# mypy will try to import cached_property but fail to find its types
# since we run mypy with the most recent python version, we can simply import
# cached_property from stdlib and we'll be fine
if TYPE_CHECKING: # pragma: no cover
from functools import cached_property
else:
try:
from functools import cached_property
except ImportError:
from cached_property import cached_property


__all__ = ["cached_property"]
Loading

0 comments on commit e3afa55

Please sign in to comment.