1
1
from __future__ import annotations
2
2
3
- from typing import TYPE_CHECKING
3
+ import os
4
+ from typing import Iterable , TYPE_CHECKING
4
5
5
6
import testcontainers .core .config
6
7
import testcontainers .core .container
11
12
if TYPE_CHECKING :
12
13
from pytest import ExitCode , Session , Parser , Metafunc
13
14
15
+ SECURITY_OPTION_ROOTLESS = "name=rootless"
16
+ TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE = "TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE"
17
+
14
18
SHUTDOWN_RYUK = False
15
19
16
20
# NOTE: Configure Testcontainers through `testcontainers.core.config` and not through env variables.
26
30
testcontainers .core .config .testcontainers_config .ryuk_privileged = True
27
31
28
32
33
+ # https://docs.pytest.org/en/latest/reference/reference.html#pytest.hookspec.pytest_addoption
29
34
def pytest_addoption (parser : Parser ) -> None :
30
35
parser .addoption ("--image" , action = "append" , default = [],
31
36
help = "Image to use, can be specified multiple times" )
32
37
33
38
39
+ # https://docs.pytest.org/en/latest/reference/reference.html#pytest.hookspec.pytest_generate_tests
34
40
def pytest_generate_tests (metafunc : Metafunc ) -> None :
35
41
if image .__name__ in metafunc .fixturenames :
36
42
metafunc .parametrize (image .__name__ , metafunc .config .getoption ("--image" ))
@@ -43,17 +49,42 @@ def image(request):
43
49
yield request .param
44
50
45
51
52
+ # https://docs.pytest.org/en/latest/reference/reference.html#pytest.hookspec.pytest_sessionstart
46
53
def pytest_sessionstart (session : Session ) -> None :
47
54
# first preflight check: ping the Docker API
48
55
client = testcontainers .core .docker_client .DockerClient ()
49
56
assert client .client .ping (), "Failed to connect to Docker"
50
57
58
+ # determine the local socket path
59
+ # NOTE: this will not work for remote docker, but we will cross the bridge when we come to it
60
+ socket_path = the_one (adapter .socket_path for adapter in client .client .api .adapters .values ())
61
+
62
+ # set that socket path for ryuk's use, unless user overrode that
63
+ if TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE not in os .environ :
64
+ testcontainers .core .config .testcontainers_config .ryuk_docker_socket = socket_path
65
+
51
66
# second preflight check: start the Reaper container
52
- assert testcontainers .core .container .Reaper .get_instance () is not None , "Failed to start Reaper container"
67
+ if not testcontainers .core .config .testcontainers_config .ryuk_disabled :
68
+ assert testcontainers .core .container .Reaper .get_instance () is not None , "Failed to start Reaper container"
53
69
54
70
55
71
# https://docs.pytest.org/en/latest/reference/reference.html#pytest.hookspec.pytest_sessionfinish
56
72
def pytest_sessionfinish (session : Session , exitstatus : int | ExitCode ) -> None :
57
73
# resolves a shutdown resource leak warning that would be otherwise reported
58
74
if SHUTDOWN_RYUK :
59
75
testcontainers .core .container .Reaper .delete_instance ()
76
+
77
+
78
+ # https://docs.python.org/3/library/functions.html#iter
79
+ def the_one [T ](iterable : Iterable [T ]) -> T :
80
+ """Checks that there is exactly one element in the iterable, and returns it."""
81
+ it = iter (iterable )
82
+ try :
83
+ v = next (it )
84
+ except StopIteration :
85
+ raise ValueError ("No elements in iterable" )
86
+ try :
87
+ next (it )
88
+ except StopIteration :
89
+ return v
90
+ raise ValueError ("More than one element in iterable" )
0 commit comments