22
33from __future__ import annotations
44
5- import time
6-
75import pytest
86
7+ from libtmux .test .retry import retry_until
8+
99
1010@pytest .fixture
1111def window (session ):
@@ -19,26 +19,31 @@ def pane(window):
1919 pane = window .active_pane
2020 # Clear the pane at the start
2121 pane .send_keys ("clear" , enter = True )
22- time .sleep (0.2 )
22+
23+ def pane_is_cleared () -> bool :
24+ pane_contents = "\n " .join (pane .capture_pane ())
25+ return "clear" not in pane_contents
26+
27+ retry_until (pane_is_cleared , 1 )
2328 return pane
2429
2530
2631def test_process_detection (pane ) -> None :
2732 """Test detecting running processes in a pane."""
2833 # Start a long-running process
29- pane .send_keys ("sleep 10 &" , enter = True ) # Run in background
30- time .sleep (0.5 )
34+ pane .send_keys ("sleep 10 &" , enter = True )
3135
3236 # Get the pane's TTY
3337 pane_tty = pane .cmd ("display-message" , "-p" , "#{pane_tty}" ).stdout [0 ]
3438
35- # Clear the pane
36- pane .send_keys ("clear" , enter = True )
37- time .sleep (0.5 )
38-
39- # Get information about the running process using system ps command
39+ # Run ps command to list processes
4040 pane .send_keys (f"ps -t { pane_tty } -o pid,command | grep sleep" , enter = True )
41- time .sleep (1 )
41+
42+ def ps_output_contains_sleep () -> bool :
43+ ps_output = pane .capture_pane ()
44+ return any ("sleep 10" in line for line in ps_output )
45+
46+ retry_until (ps_output_contains_sleep , 3 )
4247
4348 # Capture the output
4449 ps_output = pane .capture_pane ()
@@ -48,28 +53,68 @@ def test_process_detection(pane) -> None:
4853 f"Expected 'sleep 10' in: { ps_output } "
4954 )
5055
56+ # Clear the pane
57+ pane .send_keys ("clear" , enter = True )
58+
59+ def pane_is_cleared () -> bool :
60+ pane_contents = "\n " .join (pane .capture_pane ())
61+ return "clear" not in pane_contents
62+
63+ retry_until (pane_is_cleared , 1 )
64+
5165 # Kill the process (find PID and kill it)
5266 pane .send_keys ("pkill -f 'sleep 10'" , enter = True )
53- time .sleep (1 )
5467
55- # Clear the pane again
56- pane .send_keys ("clear" , enter = True )
57- time .sleep (0.5 )
68+ # Run ps command again to verify process is gone
69+ pane .send_keys (
70+ f"ps -t { pane_tty } -o pid,command | grep sleep || echo 'Process not found'" ,
71+ enter = True ,
72+ )
73+
74+ def process_is_killed () -> bool :
75+ ps_output = pane .capture_pane ()
76+ return any ("Process not found" in line for line in ps_output )
77+
78+ retry_until (process_is_killed , 3 )
5879
5980 # Verify the process has stopped
60- pane .send_keys (f"ps -t { pane_tty } -o pid,command | grep sleep" , enter = True )
61- time .sleep (1 )
6281 ps_output = pane .capture_pane ()
63- assert not any ("sleep 10" in line for line in ps_output ), (
64- f"Found 'sleep 10' in: { ps_output } "
65- )
82+
83+ # Check if there's an actual running sleep process
84+ # We need to filter out:
85+ # 1. The command line (pkill -f 'sleep 10')
86+ # 2. The grep command itself (grep sleep)
87+ # 3. The termination notice ([1] + terminated sleep 10)
88+ is_running = False
89+ for line in ps_output :
90+ # Look for a line with PID and 'sleep 10' without being a command or
91+ # termination message
92+ is_command_line = line .startswith ("d%" ) or "grep sleep" in line
93+ is_termination = "terminated" in line
94+
95+ if (
96+ "sleep 10" in line
97+ and not is_command_line
98+ and not is_termination
99+ and "Process not found" not in line
100+ ):
101+ is_running = True
102+ break
103+
104+ assert not is_running , f"Found running 'sleep 10' in: { ps_output } "
66105
67106
68107def test_command_output_scrollback (pane ) -> None :
69108 """Test handling command output that exceeds visible pane height."""
70109 # Generate a lot of output
71110 pane .send_keys ('for i in $(seq 1 100); do echo "Line $i"; done' , enter = True )
72- time .sleep (1.0 )
111+
112+ def output_generated () -> bool :
113+ output = pane .capture_pane (start = "-100" )
114+ lines_with_numbers = [line for line in output if "Line " in line ]
115+ return len (lines_with_numbers ) > 50
116+
117+ retry_until (output_generated , 3 )
73118
74119 # Capture all the scrollback buffer
75120 output = pane .capture_pane (start = "-100" )
@@ -90,7 +135,12 @@ def test_command_output_scrollback(pane) -> None:
90135
91136 # Clear the scrollback buffer
92137 pane .clear ()
93- time .sleep (0.5 )
138+
139+ def buffer_cleared () -> bool :
140+ cleared_output = pane .capture_pane ()
141+ return len ([line for line in cleared_output if line .strip ()]) <= 1
142+
143+ retry_until (buffer_cleared , 1 )
94144
95145 # Verify the buffer is now empty or only has the prompt
96146 cleared_output = pane .capture_pane ()
@@ -102,29 +152,34 @@ def test_running_background_process(pane) -> None:
102152 # Start a background process that writes to a file
103153 pane .send_keys ("touch /tmp/background_test.txt" , enter = True )
104154 pane .send_keys (
105- '(for i in $(seq 1 5); do echo "Update $i" >> /tmp/background_test.txt; sleep 1; done) &' ,
155+ "(for i in $(seq 1 5); do "
156+ "echo 'Update $i' >> /tmp/background_test.txt; "
157+ "sleep 0.1; "
158+ "done) &" ,
106159 enter = True ,
107160 )
108- time .sleep (0.5 )
109161
110162 # Send a simple command with a unique string to verify responsiveness
111163 pane .send_keys ("echo 'UNIQUE_BACKGROUND_STRING_789'" , enter = True )
112- time .sleep (1.0 )
113164
114- # Check the output contains our test string
115- for _ in range (3 ): # Try a few times if needed
165+ def unique_string_in_output () -> bool :
116166 output = pane .capture_pane ()
117- if any ("UNIQUE_BACKGROUND_STRING_789" in line for line in output ):
118- break
119- time . sleep ( 0.5 )
167+ return any ("UNIQUE_BACKGROUND_STRING_789" in line for line in output )
168+
169+ retry_until ( unique_string_in_output , 2 )
120170
121171 # Verify the command was executed
172+ output = pane .capture_pane ()
122173 assert any ("UNIQUE_BACKGROUND_STRING_789" in line for line in output )
123174
124175 # Check the file periodically
125- for _attempt in range (5 ):
126- pane .send_keys ("cat /tmp/background_test.txt" , enter = True )
127- time .sleep (1.0 )
176+ pane .send_keys ("cat /tmp/background_test.txt" , enter = True )
177+
178+ def updates_in_file () -> bool :
179+ output = pane .capture_pane ()
180+ return any ("Update" in line for line in output )
181+
182+ retry_until (updates_in_file , 3 )
128183
129184 # Verify we got at least some updates
130185 output = pane .capture_pane ()
0 commit comments