Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7aa5f86

Browse files
test(probes): add regression test demonstrating parallel logging initializer fix
Signed-off-by: Varun Nuthalapati <[email protected]>
1 parent 727728b commit 7aa5f86

1 file changed

Lines changed: 48 additions & 1 deletion

File tree

tests/probes/test_probes_base_parallel_logging.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88
import os
99
import tempfile
1010
from multiprocessing import Pool
11-
from unittest.mock import MagicMock
11+
from unittest.mock import MagicMock, patch
1212

1313
import pytest
1414

15+
import garak._config
16+
import garak._plugins
17+
import garak.attempt
1518
from garak.probes.base import _worker_logging_init
1619

1720

@@ -245,3 +248,47 @@ def test_parallel_worker_fds_are_independent():
245248
else:
246249
os.environ["GARAK_LOG_FILE"] = old_env
247250
os.unlink(log_path)
251+
252+
253+
# ---------------------------------------------------------------------------
254+
# Regression test: Probe._execute_all must wire up the initializer
255+
# ---------------------------------------------------------------------------
256+
257+
258+
def test_execute_all_passes_logging_initializer_to_pool():
259+
"""Probe._execute_all must construct its worker Pool with
260+
initializer=_worker_logging_init. Without this wiring, forked workers
261+
inherit the parent's log FileHandler and share its file descriptor,
262+
which can raise a reentrant-flush RuntimeError under concurrent writes
263+
(issue #1355). This test fails if the initializer argument is removed."""
264+
with open(os.devnull, "w+", encoding="utf-8") as fh:
265+
garak._config.load_base_config()
266+
garak._config.transient.reportfile = fh
267+
268+
p = garak._plugins.load_plugin(
269+
"probes.test.Test", config_root=garak._config
270+
)
271+
g = garak._plugins.load_plugin(
272+
"generators.test.Repeat", config_root=garak._config
273+
)
274+
p.generator = g
275+
p.parallel_attempts = 2
276+
277+
attempts = [
278+
garak.attempt.Attempt(prompt=garak.attempt.Message("test one")),
279+
garak.attempt.Attempt(prompt=garak.attempt.Message("test two")),
280+
]
281+
282+
real_pool = Pool
283+
284+
with patch("multiprocessing.Pool", wraps=real_pool) as mock_pool:
285+
p._execute_all(attempts)
286+
287+
garak._config.transient.reportfile = None
288+
289+
assert mock_pool.called, "Probe._execute_all should use a worker Pool"
290+
_, kwargs = mock_pool.call_args
291+
assert kwargs.get("initializer") is _worker_logging_init, (
292+
"Probe._execute_all must pass _worker_logging_init as the Pool "
293+
"initializer to avoid shared log file descriptors in workers"
294+
)

0 commit comments

Comments
 (0)