From 63c7f42ab4ea27241559096b7c1885ef3c2cd642 Mon Sep 17 00:00:00 2001 From: Roland Walker Date: Sat, 28 Feb 2026 12:04:07 -0500 Subject: [PATCH] fix tempfile leak in behave test suite preferring NamedTemporaryFile over mkstemp --- changelog.md | 1 + test/features/environment.py | 15 ++++++++++----- test/test_config.py | 22 +++++++++++----------- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/changelog.md b/changelog.md index ed5181e8..5b1d5f98 100644 --- a/changelog.md +++ b/changelog.md @@ -22,6 +22,7 @@ Internal * Avoid depending on string matches into host info. * Add more URL constants. * Set `$VISUAL` whenever `$EDITOR` is set. +* Fix tempfile leak in test suite. 1.58.0 (2026/02/28) diff --git a/test/features/environment.py b/test/features/environment.py index f0b092fb..c8189631 100644 --- a/test/features/environment.py +++ b/test/features/environment.py @@ -3,13 +3,14 @@ import os import shutil import sys -from tempfile import mkstemp +from tempfile import NamedTemporaryFile import db_utils as dbutils import fixture_utils as fixutils import pexpect from steps.wrappers import run_cli, wait_prompt +from test.utils import TEMPFILE_PREFIX test_log_file = os.path.join(os.environ["HOME"], ".mycli.test.log") @@ -65,13 +66,12 @@ def before_all(context): "pager_boundary": "---boundary---", } - _, my_cnf = mkstemp() - with open(my_cnf, "w") as f: - f.write( + with NamedTemporaryFile(prefix=TEMPFILE_PREFIX, mode='w', delete=False) as my_cnf: + my_cnf.write( f'[client]\npager={sys.executable} ' f'{os.path.join(context.package_root, "test/features/wrappager.py")} {context.conf["pager_boundary"]}\n' ) - context.conf["defaults-file"] = my_cnf + context.conf["defaults-file"] = my_cnf.name context.conf["myclirc"] = os.path.join(context.package_root, "test", "myclirc") context.cn = dbutils.create_db( @@ -85,6 +85,11 @@ def after_all(context): """Unset env parameters.""" dbutils.close_cn(context.cn) dbutils.drop_db(context.conf["host"], context.conf["port"], context.conf["user"], context.conf["pass"], context.conf["dbname"]) + try: + if os.path.exists(context.conf["defaults-file"]): + os.remove(context.conf["defaults-file"]) + except Exception: + pass # Restore env vars. # for k, v in context.pgenv.items(): diff --git a/test/test_config.py b/test/test_config.py index 4ef19bcb..1033a84c 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -6,7 +6,7 @@ import os import struct import sys -import tempfile +from tempfile import NamedTemporaryFile import pytest @@ -18,6 +18,7 @@ str_to_bool, strip_matching_quotes, ) +from test.utils import TEMPFILE_PREFIX LOGIN_PATH_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "mylogin.cnf")) @@ -109,18 +110,17 @@ def test_get_mylogin_cnf_path(monkeypatch): def test_alternate_get_mylogin_cnf_path(monkeypatch): """Tests that the alternate path for .mylogin.cnf is detected.""" - fd, temp_path = tempfile.mkstemp() - monkeypatch.setenv('MYSQL_TEST_LOGIN_FILE', temp_path) - - login_cnf_path = get_mylogin_cnf_path() - - assert temp_path == login_cnf_path + with NamedTemporaryFile(prefix=TEMPFILE_PREFIX, mode='w', delete=False) as login_file: + monkeypatch.setenv('MYSQL_TEST_LOGIN_FILE', login_file.name) + login_cnf_path = get_mylogin_cnf_path() try: - os.close(fd) - os.remove(temp_path) - except Exception: - pass + assert login_file.name == login_cnf_path + except AssertionError as e: + assert AssertionError(e) + finally: + if os.path.exists(login_file.name): + os.remove(login_file.name) def test_str_to_bool():