Skip to content

Commit be06ede

Browse files
authored
✅ close DockerClient instances in test fixtures (#130)
1 parent 99ff2e0 commit be06ede

1 file changed

Lines changed: 77 additions & 63 deletions

File tree

tests/conftest.py

Lines changed: 77 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -94,21 +94,27 @@ def pytest_addoption(parser: "Parser"):
9494
def cleanup_hanged_docker_containers() -> None:
9595
try:
9696
client: DockerClient = docker.from_env()
97-
for container in client.containers.list():
98-
if container.name == "pytest_mysql_to_sqlite3":
99-
container.kill()
100-
break
97+
try:
98+
for container in client.containers.list():
99+
if container.name == "pytest_mysql_to_sqlite3":
100+
container.kill()
101+
break
102+
finally:
103+
client.close()
101104
except Exception:
102105
pass
103106

104107

105-
def pytest_keyboard_interrupt() -> None:
108+
def pytest_keyboard_interrupt(excinfo: t.Any) -> None:
106109
try:
107110
client: DockerClient = docker.from_env()
108-
for container in client.containers.list():
109-
if container.name == "pytest_mysql_to_sqlite3":
110-
container.kill()
111-
break
111+
try:
112+
for container in client.containers.list():
113+
if container.name == "pytest_mysql_to_sqlite3":
114+
container.kill()
115+
break
116+
finally:
117+
client.close()
112118
except Exception:
113119
pass
114120

@@ -195,6 +201,7 @@ def mysql_credentials(pytestconfig: Config) -> MySQLCredentials:
195201

196202
@pytest.fixture(scope="session")
197203
def mysql_instance(mysql_credentials: MySQLCredentials, pytestconfig: Config) -> t.Iterator[MySQLConnection]:
204+
client: t.Optional[DockerClient] = None
198205
container: t.Optional[Container] = None
199206
mysql_connection: t.Optional[t.Union[PooledMySQLConnection, MySQLConnectionAbstract]] = None
200207
mysql_available: bool = False
@@ -215,62 +222,69 @@ def mysql_instance(mysql_credentials: MySQLCredentials, pytestconfig: Config) ->
215222
except Exception as err:
216223
pytest.fail(str(err))
217224

218-
docker_mysql_image = pytestconfig.getoption("docker_mysql_image") or "mysql:latest"
219-
220-
if not any(docker_mysql_image in image.tags for image in client.images.list()):
221-
print(f"Attempting to download Docker image {docker_mysql_image}'")
222-
try:
223-
client.images.pull(docker_mysql_image)
224-
except (HTTPError, NotFound) as err:
225-
pytest.fail(str(err))
226-
227-
container = client.containers.run(
228-
image=docker_mysql_image,
229-
name="pytest_mysql_to_sqlite3",
230-
ports={"3306/tcp": (mysql_credentials.host, f"{mysql_credentials.port}/tcp")},
231-
environment={
232-
"MYSQL_RANDOM_ROOT_PASSWORD": "yes",
233-
"MYSQL_USER": mysql_credentials.user,
234-
"MYSQL_PASSWORD": mysql_credentials.password,
235-
"MYSQL_DATABASE": mysql_credentials.database,
236-
},
237-
command=[
238-
"--character-set-server=utf8mb4",
239-
"--collation-server=utf8mb4_unicode_ci",
240-
],
241-
detach=True,
242-
auto_remove=True,
243-
)
244-
245-
while not mysql_available and mysql_connection_retries > 0:
246-
try:
247-
mysql_connection = mysql.connector.connect(
248-
user=mysql_credentials.user,
249-
password=mysql_credentials.password,
250-
host=mysql_credentials.host,
251-
port=mysql_credentials.port,
252-
charset="utf8mb4",
253-
collation="utf8mb4_unicode_ci",
225+
try:
226+
if use_docker:
227+
docker_mysql_image = pytestconfig.getoption("docker_mysql_image") or "mysql:latest"
228+
229+
if not any(docker_mysql_image in image.tags for image in client.images.list()):
230+
print(f"Attempting to download Docker image {docker_mysql_image}'")
231+
try:
232+
client.images.pull(docker_mysql_image)
233+
except (HTTPError, NotFound) as err:
234+
pytest.fail(str(err))
235+
236+
container = client.containers.run(
237+
image=docker_mysql_image,
238+
name="pytest_mysql_to_sqlite3",
239+
ports={"3306/tcp": (mysql_credentials.host, f"{mysql_credentials.port}/tcp")},
240+
environment={
241+
"MYSQL_RANDOM_ROOT_PASSWORD": "yes",
242+
"MYSQL_USER": mysql_credentials.user,
243+
"MYSQL_PASSWORD": mysql_credentials.password,
244+
"MYSQL_DATABASE": mysql_credentials.database,
245+
},
246+
command=[
247+
"--character-set-server=utf8mb4",
248+
"--collation-server=utf8mb4_unicode_ci",
249+
],
250+
detach=True,
251+
auto_remove=True,
254252
)
255-
except mysql.connector.Error as err:
256-
if err.errno == errorcode.CR_SERVER_LOST:
257-
# sleep for two seconds and retry the connection
258-
sleep(2)
259-
else:
260-
raise
261-
finally:
262-
mysql_connection_retries -= 1
263-
if mysql_connection and mysql_connection.is_connected():
264-
mysql_available = True
265-
mysql_connection.close()
266-
else:
267-
if not mysql_available and mysql_connection_retries <= 0:
268-
raise ConnectionAbortedError("Maximum MySQL connection retries exhausted! Are you sure MySQL is running?")
269-
270-
yield # type: ignore[misc]
271253

272-
if use_docker and container is not None:
273-
container.kill()
254+
while not mysql_available and mysql_connection_retries > 0:
255+
try:
256+
mysql_connection = mysql.connector.connect(
257+
user=mysql_credentials.user,
258+
password=mysql_credentials.password,
259+
host=mysql_credentials.host,
260+
port=mysql_credentials.port,
261+
charset="utf8mb4",
262+
collation="utf8mb4_unicode_ci",
263+
)
264+
except mysql.connector.Error as err:
265+
if err.errno == errorcode.CR_SERVER_LOST:
266+
# sleep for two seconds and retry the connection
267+
sleep(2)
268+
else:
269+
raise
270+
finally:
271+
mysql_connection_retries -= 1
272+
if mysql_connection and mysql_connection.is_connected():
273+
mysql_available = True
274+
mysql_connection.close()
275+
else:
276+
if not mysql_available and mysql_connection_retries <= 0:
277+
raise ConnectionAbortedError("Maximum MySQL connection retries exhausted! Are you sure MySQL is running?")
278+
279+
yield # type: ignore[misc]
280+
finally:
281+
if use_docker:
282+
try:
283+
if container is not None:
284+
container.kill()
285+
finally:
286+
if client is not None:
287+
client.close()
274288

275289

276290
class MySQLSSLCerts(t.NamedTuple):

0 commit comments

Comments
 (0)