Skip to content

Commit 4cab85c

Browse files
Add environment diagnostic script for Windows CI differences
This script collects detailed information about: - Windows version and build - Python version and subprocess configuration - Job Objects support - Security software - Process creation timing - Handle inheritance settings This will help identify differences between local dev environments (where the test passes) and CI environments (where it flakes).
1 parent 79e5ce7 commit 4cab85c

File tree

2 files changed

+152
-0
lines changed

2 files changed

+152
-0
lines changed
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#!/usr/bin/env pwsh
2+
# Script to diagnose environment differences that might cause CI flakiness
3+
# Usage: .\diagnose-environment.ps1
4+
5+
Write-Host "Diagnosing Windows environment for stdio test issues..." -ForegroundColor Cyan
6+
Write-Host ""
7+
8+
# System Information
9+
Write-Host "=== SYSTEM INFORMATION ===" -ForegroundColor Yellow
10+
Write-Host "Windows Version:"
11+
(Get-CimInstance Win32_OperatingSystem).Version
12+
Write-Host "Windows Build:"
13+
(Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion").DisplayVersion
14+
Write-Host ""
15+
16+
# Python Information
17+
Write-Host "=== PYTHON INFORMATION ===" -ForegroundColor Yellow
18+
Write-Host "Python Version:"
19+
python --version
20+
Write-Host ""
21+
Write-Host "Python Build Info:"
22+
python -c "import sys; print(f'Version: {sys.version}')"
23+
python -c "import sys; print(f'Platform: {sys.platform}')"
24+
python -c "import sys; print(f'Windows Version: {sys.getwindowsversion()}')"
25+
Write-Host ""
26+
27+
# Check subprocess configuration
28+
Write-Host "=== SUBPROCESS CONFIGURATION ===" -ForegroundColor Yellow
29+
python -c @"
30+
import subprocess
31+
import sys
32+
print(f'CREATE_NO_WINDOW available: {hasattr(subprocess, "CREATE_NO_WINDOW")}')
33+
print(f'CREATE_NEW_PROCESS_GROUP available: {hasattr(subprocess, "CREATE_NEW_PROCESS_GROUP")}')
34+
print(f'Windows subprocess startup info: {hasattr(subprocess, "STARTUPINFO")}')
35+
36+
# Check handle inheritance defaults
37+
import os
38+
print(f'\nHandle inheritance (os.O_NOINHERIT): {hasattr(os, "O_NOINHERIT")}')
39+
40+
# Check asyncio event loop
41+
import asyncio
42+
try:
43+
loop = asyncio.get_event_loop_policy()
44+
print(f'Event loop policy: {type(loop).__name__}')
45+
except:
46+
print('Event loop policy: Unable to determine')
47+
"@
48+
Write-Host ""
49+
50+
# Check for Job Objects support
51+
Write-Host "=== JOB OBJECTS SUPPORT ===" -ForegroundColor Yellow
52+
python -c @"
53+
try:
54+
import win32job
55+
import win32api
56+
print('pywin32 available: Yes')
57+
print(f'win32job version: {win32job.__file__}')
58+
59+
# Try to create a job object
60+
try:
61+
job = win32job.CreateJobObject(None, '')
62+
win32api.CloseHandle(job)
63+
print('Job Object creation: Success')
64+
except Exception as e:
65+
print(f'Job Object creation: Failed - {e}')
66+
except ImportError:
67+
print('pywin32 available: No (Job Objects not available)')
68+
"@
69+
Write-Host ""
70+
71+
# Check process limits
72+
Write-Host "=== PROCESS LIMITS ===" -ForegroundColor Yellow
73+
python -c @"
74+
import os
75+
import psutil
76+
proc = psutil.Process(os.getpid())
77+
print(f'Open handles: {proc.num_handles()}')
78+
print(f'Open files: {len(proc.open_files())}')
79+
80+
# Check system-wide limits
81+
print(f'Total processes: {len(psutil.pids())}')
82+
"@
83+
Write-Host ""
84+
85+
# Check security software
86+
Write-Host "=== SECURITY SOFTWARE ===" -ForegroundColor Yellow
87+
Get-CimInstance -Namespace "root\SecurityCenter2" -ClassName AntiVirusProduct -ErrorAction SilentlyContinue |
88+
Select-Object displayName, productState | Format-Table
89+
Write-Host ""
90+
91+
# Test rapid process creation
92+
Write-Host "=== RAPID PROCESS CREATION TEST ===" -ForegroundColor Yellow
93+
Write-Host "Testing rapid tee process creation/destruction..."
94+
$testScript = @'
95+
import time
96+
import subprocess
97+
import sys
98+
99+
failures = 0
100+
times = []
101+
102+
for i in range(20):
103+
start = time.time()
104+
try:
105+
# Create process with same flags as stdio client
106+
proc = subprocess.Popen(
107+
['tee'],
108+
stdin=subprocess.PIPE,
109+
stdout=subprocess.PIPE,
110+
stderr=subprocess.PIPE,
111+
creationflags=getattr(subprocess, 'CREATE_NO_WINDOW', 0)
112+
)
113+
proc.stdin.close()
114+
proc.wait(timeout=0.5)
115+
elapsed = time.time() - start
116+
times.append(elapsed)
117+
except Exception as e:
118+
failures += 1
119+
print(f" Iteration {i+1}: FAILED - {e}")
120+
121+
if (i+1) % 5 == 0:
122+
avg_time = sum(times) / len(times) if times else 0
123+
print(f" Completed {i+1}/20 (avg: {avg_time*1000:.1f}ms)")
124+
125+
print(f"\nFailures: {failures}/20")
126+
if times:
127+
print(f"Average time: {sum(times)/len(times)*1000:.1f}ms")
128+
print(f"Max time: {max(times)*1000:.1f}ms")
129+
'@
130+
131+
python -c $testScript
132+
Write-Host ""
133+
134+
# Environment variables that might affect subprocess
135+
Write-Host "=== RELEVANT ENVIRONMENT VARIABLES ===" -ForegroundColor Yellow
136+
@("COMSPEC", "PATH", "PYTHONPATH", "PYTHONASYNCIODEBUG") | ForEach-Object {
137+
$value = [Environment]::GetEnvironmentVariable($_)
138+
if ($value) {
139+
Write-Host "$_`:"
140+
Write-Host " $value" -ForegroundColor Gray
141+
}
142+
}
143+
Write-Host ""
144+
145+
Write-Host "=== DIAGNOSIS COMPLETE ===" -ForegroundColor Cyan
146+
Write-Host ""
147+
Write-Host "Share this output when reporting the flakiness issue." -ForegroundColor Yellow
148+
Write-Host "Key differences to look for between local and CI:" -ForegroundColor Yellow
149+
Write-Host " - Windows version/build" -ForegroundColor Gray
150+
Write-Host " - Python build details" -ForegroundColor Gray
151+
Write-Host " - Security software presence" -ForegroundColor Gray
152+
Write-Host " - Process creation timing" -ForegroundColor Gray

scripts/windows-debug/test.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)