Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .beads/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# toolchain.beads.server (machine-wide shared Dolt server facts).
# Owned ledger config: the workspace root owns this tracker; conform
# initializes and verifies it against the pinned binary.
issue-prefix: "mro"
issue-prefix: "flext"

# Dolt server connection (Gas Town town server on :3307).
# The `flext` database lives there; a repository-local server is never used.
Expand Down
4 changes: 2 additions & 2 deletions .mise.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ tokei = "14.0"
"github:qltysh/qlty" = "0.642"
# Go runtime for the Go projects in this workspace.
go = "1.26"
[tools."github:marlon-costa-dc/beads"]
version = "latest"
[tools."github:gastownhall/beads"]
version = "1.2.2"
prerelease = true
minimum_release_age = "0s"

Expand Down
8 changes: 8 additions & 0 deletions src/flext_tests/_constants/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ class FlextTestsConstantsDocker:
ENV_CI: Final[str] = "CI"
CI_MAKE_VALUE: Final[str] = "Y"
DOCKER_CI_SKIP_REASON: Final[str] = "docker disabled under CI=Y"
DOCKER_CONNECTIVITY_MARKER: Final[str] = "docker"
DOCKER_UNREACHABLE_SKIP_REASON: Final[str] = (
"Docker daemon unreachable; start it to run Docker integration tests"
)
# Default probe ceiling for callers that omit max_wait. Under CI=Y the
# Docker lifecycle skips before probing. Outside CI, shared-container
# startup_timeout remains the SSOT for long boots (Oracle/kind).
Expand All @@ -38,6 +42,10 @@ class FlextTestsConstantsDocker:
"ldap": "flext-openldap-test",
"kubernetes": "flext-kind-test",
}
CONNECTIVITY_MARKERS: Final[tuple[str, ...]] = (
DOCKER_CONNECTIVITY_MARKER,
*CONNECTIVITY_MARKER_CONTAINERS,
)
UNREACHABLE_SKIP_REASON: Final[str] = (
"{marker} service unreachable at {host}:{port}; start it to run these tests"
)
Expand Down
14 changes: 13 additions & 1 deletion src/flext_tests/_fixtures/connectivity.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ def _unreachable_reason(marker: str) -> str | None:
"""Return a skip reason when the marker's service cannot be reached."""
if marker in _probe_cache:
return _probe_cache[marker]
if marker == c.Tests.DOCKER_CONNECTIVITY_MARKER:
from flext_tests.docker import FlextTestsDocker

manager = FlextTestsDocker()
client = manager.client
if client is None:
reason = c.Tests.DOCKER_UNREACHABLE_SKIP_REASON
else:
client.close()
reason = None
_probe_cache[marker] = reason
return reason
reason: str | None = None
container = c.Tests.CONNECTIVITY_MARKER_CONTAINERS.get(marker)
endpoint = None if container is None else _endpoint(container)
Expand All @@ -69,7 +81,7 @@ def pytest_collection_modifyitems(
"""Mark connectivity-bound tests as skipped when their service is down."""
del config
for item in items:
for marker in c.Tests.CONNECTIVITY_MARKER_CONTAINERS:
for marker in c.Tests.CONNECTIVITY_MARKERS:
if item.get_closest_marker(marker) is None:
continue
reason = _unreachable_reason(marker)
Expand Down
17 changes: 15 additions & 2 deletions src/flext_tests/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@

import pytest
from docker import DockerClient as DockerSDKClient, from_env as docker_from_env
from docker.constants import DEFAULT_DOCKER_API_VERSION
from docker.errors import DockerException, NotFound
from docker.transport import UnixHTTPAdapter
from python_on_whales import DockerClient as WhalesDockerClient
from python_on_whales.exceptions import DockerException as WhalesDockerException

Expand Down Expand Up @@ -130,11 +132,22 @@ def model_post_init(self, __context: t.JsonValue | None, /) -> None:
@property
def client(self) -> DockerSDKClient | None:
"""Docker client with lazy initialization."""
if self.docker_client is None:
if self.docker_client is None and self.client_error is None:
client: DockerSDKClient | None = None
try:
self.docker_client = docker_from_env()
client = docker_from_env(version=DEFAULT_DOCKER_API_VERSION)
adapter = client.api.get_adapter(client.api.base_url)
if (
isinstance(adapter, UnixHTTPAdapter)
and not Path(adapter.socket_path).exists()
):
raise FileNotFoundError(adapter.socket_path)
_ = client.ping()
self.docker_client = client
self.client_error = None
except (DockerException, OSError, TypeError, ValueError) as error:
if client is not None:
client.close()
self.logger.exception(
"Failed to initialize Docker client", error=str(error)
)
Expand Down
Loading