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