2
2
3
3
from __future__ import annotations
4
4
5
- import time
6
-
7
5
import pytest
8
6
7
+ from libtmux .test .retry import retry_until
8
+
9
9
10
10
@pytest .fixture
11
11
def window (session ):
@@ -19,26 +19,31 @@ def pane(window):
19
19
pane = window .active_pane
20
20
# Clear the pane at the start
21
21
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 )
23
28
return pane
24
29
25
30
26
31
def test_process_detection (pane ) -> None :
27
32
"""Test detecting running processes in a pane."""
28
33
# 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 )
31
35
32
36
# Get the pane's TTY
33
37
pane_tty = pane .cmd ("display-message" , "-p" , "#{pane_tty}" ).stdout [0 ]
34
38
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
40
40
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 )
42
47
43
48
# Capture the output
44
49
ps_output = pane .capture_pane ()
@@ -48,28 +53,68 @@ def test_process_detection(pane) -> None:
48
53
f"Expected 'sleep 10' in: { ps_output } "
49
54
)
50
55
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
+
51
65
# Kill the process (find PID and kill it)
52
66
pane .send_keys ("pkill -f 'sleep 10'" , enter = True )
53
- time .sleep (1 )
54
67
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 )
58
79
59
80
# 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 )
62
81
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 } "
66
105
67
106
68
107
def test_command_output_scrollback (pane ) -> None :
69
108
"""Test handling command output that exceeds visible pane height."""
70
109
# Generate a lot of output
71
110
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 )
73
118
74
119
# Capture all the scrollback buffer
75
120
output = pane .capture_pane (start = "-100" )
@@ -90,7 +135,12 @@ def test_command_output_scrollback(pane) -> None:
90
135
91
136
# Clear the scrollback buffer
92
137
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 )
94
144
95
145
# Verify the buffer is now empty or only has the prompt
96
146
cleared_output = pane .capture_pane ()
@@ -102,29 +152,34 @@ def test_running_background_process(pane) -> None:
102
152
# Start a background process that writes to a file
103
153
pane .send_keys ("touch /tmp/background_test.txt" , enter = True )
104
154
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) &" ,
106
159
enter = True ,
107
160
)
108
- time .sleep (0.5 )
109
161
110
162
# Send a simple command with a unique string to verify responsiveness
111
163
pane .send_keys ("echo 'UNIQUE_BACKGROUND_STRING_789'" , enter = True )
112
- time .sleep (1.0 )
113
164
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 :
116
166
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 )
120
170
121
171
# Verify the command was executed
172
+ output = pane .capture_pane ()
122
173
assert any ("UNIQUE_BACKGROUND_STRING_789" in line for line in output )
123
174
124
175
# 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 )
128
183
129
184
# Verify we got at least some updates
130
185
output = pane .capture_pane ()
0 commit comments