22
33from __future__ import annotations
44
5+ import json
6+ from pathlib import Path
7+
58import pytest
69
710from autoskillit .core import CmdSpec
11+ from autoskillit .core .types import SubprocessResult , TerminationReason
812
913pytestmark = [pytest .mark .layer ("execution" ), pytest .mark .small ]
1014
1115
16+ def _success_result () -> SubprocessResult :
17+ return SubprocessResult (
18+ returncode = 0 ,
19+ stdout = json .dumps (
20+ {
21+ "type" : "result" ,
22+ "subtype" : "success" ,
23+ "is_error" : False ,
24+ "result" : "done" ,
25+ "session_id" : "sess-idle-test" ,
26+ }
27+ ),
28+ stderr = "" ,
29+ termination = TerminationReason .NATURAL_EXIT ,
30+ pid = 12345 ,
31+ )
32+
33+
1234def test_assert_headless_cmd_passes_with_p_flag () -> None :
1335 from autoskillit .execution .headless ._headless_helpers import assert_headless_cmd
1436
@@ -32,3 +54,85 @@ def test_assert_headless_cmd_empty_cmd_no_error() -> None:
3254 from autoskillit .execution .headless ._headless_helpers import assert_headless_cmd
3355
3456 assert_headless_cmd (CmdSpec (cmd = (), env = {}))
57+
58+
59+ class TestProcessIdleTimeoutOverride :
60+ """Tests for CmdSpec.process_idle_timeout_ms overriding effective_idle."""
61+
62+ @pytest .mark .anyio
63+ async def test_spec_idle_used_when_caller_supplies_none (
64+ self , minimal_ctx , tmp_path : Path , monkeypatch
65+ ) -> None :
66+ from autoskillit .execution .headless import run_headless_core
67+ from tests .execution .conftest import _mock_backend
68+ from tests .fakes import MockSubprocessRunner
69+
70+ monkeypatch .delenv ("AUTOSKILLIT_IDLE_OUTPUT_TIMEOUT" , raising = False )
71+ runner = MockSubprocessRunner ()
72+ runner .set_default (_success_result ())
73+ minimal_ctx .runner = runner
74+ backend = _mock_backend (pty_required = True , channel_b_capable = True )
75+ backend .build_skill_session_cmd .return_value = CmdSpec (
76+ cmd = ("claude" , "-p" , "test" ),
77+ env = {},
78+ process_idle_timeout_ms = 30000 ,
79+ )
80+ minimal_ctx .backend = backend
81+
82+ await run_headless_core ("/test foo" , str (tmp_path ), minimal_ctx )
83+
84+ assert runner .call_args_list , "runner was never called"
85+ _cmd , _cwd , _timeout , kwargs = runner .call_args_list [0 ]
86+ assert kwargs .get ("idle_output_timeout" ) == 30.0
87+
88+ @pytest .mark .anyio
89+ async def test_spec_idle_overrides_when_smaller (
90+ self , minimal_ctx , tmp_path : Path , monkeypatch
91+ ) -> None :
92+ from autoskillit .execution .headless import run_headless_core
93+ from tests .execution .conftest import _mock_backend
94+ from tests .fakes import MockSubprocessRunner
95+
96+ monkeypatch .setenv ("AUTOSKILLIT_IDLE_OUTPUT_TIMEOUT" , "45" )
97+ runner = MockSubprocessRunner ()
98+ runner .set_default (_success_result ())
99+ minimal_ctx .runner = runner
100+ backend = _mock_backend (pty_required = True , channel_b_capable = True )
101+ backend .build_skill_session_cmd .return_value = CmdSpec (
102+ cmd = ("claude" , "-p" , "test" ),
103+ env = {},
104+ process_idle_timeout_ms = 15000 ,
105+ )
106+ minimal_ctx .backend = backend
107+
108+ await run_headless_core ("/test foo" , str (tmp_path ), minimal_ctx )
109+
110+ assert runner .call_args_list , "runner was never called"
111+ _cmd , _cwd , _timeout , kwargs = runner .call_args_list [0 ]
112+ assert kwargs .get ("idle_output_timeout" ) == 15.0
113+
114+ @pytest .mark .anyio
115+ async def test_zero_spec_idle_leaves_effective_unaffected (
116+ self , minimal_ctx , tmp_path : Path , monkeypatch
117+ ) -> None :
118+ from autoskillit .execution .headless import run_headless_core
119+ from tests .execution .conftest import _mock_backend
120+ from tests .fakes import MockSubprocessRunner
121+
122+ monkeypatch .setenv ("AUTOSKILLIT_IDLE_OUTPUT_TIMEOUT" , "30" )
123+ runner = MockSubprocessRunner ()
124+ runner .set_default (_success_result ())
125+ minimal_ctx .runner = runner
126+ backend = _mock_backend (pty_required = True , channel_b_capable = True )
127+ backend .build_skill_session_cmd .return_value = CmdSpec (
128+ cmd = ("claude" , "-p" , "test" ),
129+ env = {},
130+ process_idle_timeout_ms = 0 ,
131+ )
132+ minimal_ctx .backend = backend
133+
134+ await run_headless_core ("/test foo" , str (tmp_path ), minimal_ctx )
135+
136+ assert runner .call_args_list , "runner was never called"
137+ _cmd , _cwd , _timeout , kwargs = runner .call_args_list [0 ]
138+ assert kwargs .get ("idle_output_timeout" ) == 30.0
0 commit comments