1515
1616"""Tests for the reusable lmms-eval checkpoint backend."""
1717
18+ import asyncio
1819import json
1920import os
21+ import signal
2022import sys
2123from pathlib import Path
2224
@@ -216,6 +218,16 @@ def test_command_rejects_reserved_extra_args_setting(tmp_path, extra_args, expec
216218 assert expected in str (exc_info .value )
217219
218220
221+ @pytest .mark .parametrize ("extra_args" , [b"--verbosity DEBUG" , bytearray (b"--verbosity DEBUG" )])
222+ def test_command_rejects_byte_string_extra_args (tmp_path , extra_args ):
223+ with pytest .raises (TypeError , match = "extra_args must be a string or sequence" ):
224+ lmms ._build_command (
225+ {** _settings ("ifeval" ), "extra_args" : extra_args },
226+ checkpoint = "/ckpts/candidate" ,
227+ output_path = tmp_path / "results" ,
228+ )
229+
230+
219231@pytest .mark .skipif (os .name != "posix" , reason = "process groups are POSIX-specific" )
220232def test_timeout_kills_ignored_process_group_members (monkeypatch , tmp_path ):
221233 script = (
@@ -239,6 +251,53 @@ def test_timeout_kills_ignored_process_group_members(monkeypatch, tmp_path):
239251 assert exc_info .value .stderr == ""
240252
241253
254+ def test_legacy_asyncio_timeout_is_classified (monkeypatch , tmp_path ):
255+ class LegacyAsyncioTimeoutError (Exception ):
256+ pass
257+
258+ class Process :
259+ pid = 123
260+ returncode = None
261+
262+ async def wait (self ):
263+ return self .returncode
264+
265+ process = Process ()
266+ wait_calls = 0
267+
268+ async def create_subprocess_exec (* _args , ** _kwargs ):
269+ return process
270+
271+ async def wait_for (awaitable , _timeout ):
272+ nonlocal wait_calls
273+ wait_calls += 1
274+ awaitable .close ()
275+ if wait_calls == 1 :
276+ raise LegacyAsyncioTimeoutError
277+ process .returncode = - signal .SIGTERM
278+ return process .returncode
279+
280+ monkeypatch .setattr (
281+ lmms ,
282+ "_TIMEOUT_ERRORS" ,
283+ (TimeoutError , LegacyAsyncioTimeoutError ),
284+ )
285+ monkeypatch .setattr (lmms .asyncio , "create_subprocess_exec" , create_subprocess_exec )
286+ monkeypatch .setattr (lmms .asyncio , "wait_for" , wait_for )
287+ monkeypatch .setattr (lmms , "_signal_process_group" , lambda * _args : None )
288+ monkeypatch .setattr (lmms , "_process_group_exists" , lambda _process : False )
289+
290+ with pytest .raises (lmms .LmmsEvalTimeoutError ):
291+ asyncio .run (
292+ lmms ._run_process_async (
293+ [sys .executable , "-c" , "pass" ],
294+ cwd = str (tmp_path ),
295+ env = os .environ .copy (),
296+ timeout = 1.0 ,
297+ )
298+ )
299+
300+
242301def test_run_checkpoint_flattens_metrics_and_preserves_artifacts (monkeypatch , tmp_path ):
243302 checkpoint = tmp_path / "checkpoint"
244303 checkpoint .mkdir ()
@@ -275,6 +334,8 @@ def fake_run(argv, *, cwd, env, timeout):
275334 assert Path (result ["stderr_path" ]).read_text () == ""
276335 summary = json .loads (Path (result ["result_path" ]).read_text ())
277336 assert summary ["checkpoint" ] == str (checkpoint .resolve ())
337+ assert summary ["raw_result_path" ] == result ["raw_result_path" ]
338+ assert "result_path" not in summary
278339 assert summary ["sample_counts" ] == {"gsm8k" : 4.0 , "ifeval" : 4.0 }
279340
280341
0 commit comments