test: gracefully skip test_ai_tui_agent_harness on Windows

Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
google-labs-jules[bot]andPR0M3TH3AN committed 2026-02-28 03:32:48 +00:00
1 parent b8b331b42e
commit 6db570f2a7
3 files changed
+70 -17

No files matched your search

+33
View File
@@ -6,6 +6,9 @@ import sys
import pytest
pytest.importorskip("pty")
pytest.importorskip("termios")
def _load_harness_module():
repo_root = Path(__file__).resolve().parents[2]
@@ -14,14 +17,24 @@ def _load_harness_module():
assert spec is not None and spec.loader is not None
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
try:
spec.loader.exec_module(module)
except ModuleNotFoundError as e:
pytest.skip(f"Skipping test due to missing module: {e}")
return module
try:
harness = _load_harness_module()
except pytest.skip.Exception:
harness = None
def test_run_step_records_passed_result():
if not harness:
pytest.skip("Harness not loaded")
results = []
called = {"value": False}
@@ -38,6 +51,8 @@ def test_run_step_records_passed_result():
def test_run_step_records_failed_result_and_reraises():
if not harness:
pytest.skip("Harness not loaded")
results = []
def _boom():
@@ -53,6 +68,9 @@ def test_run_step_records_failed_result_and_reraises():
def test_add_entry_menu_open_waits_when_choice_omitted():
if not harness:
pytest.skip("Harness not loaded")
class Runner:
def __init__(self):
self.sent = []
@@ -72,6 +90,9 @@ def test_add_entry_menu_open_waits_when_choice_omitted():
def test_add_entry_menu_open_sends_choice_when_provided():
if not harness:
pytest.skip("Harness not loaded")
class Runner:
def __init__(self):
self.sent = []
@@ -92,6 +113,9 @@ def test_add_entry_menu_open_sends_choice_when_provided():
def test_complete_onboarding_reaches_main_menu_and_sends_password():
if not harness:
pytest.skip("Harness not loaded")
class Runner:
def __init__(self):
self.calls = [
@@ -122,6 +146,9 @@ def test_complete_onboarding_reaches_main_menu_and_sends_password():
def test_complete_onboarding_times_out_without_expected_prompts():
if not harness:
pytest.skip("Harness not loaded")
class Runner:
def try_wait_for(self, pattern, timeout):
return False
@@ -138,6 +165,9 @@ def test_complete_onboarding_times_out_without_expected_prompts():
def test_drain_to_main_menu_uses_helper_prompt_then_returns():
if not harness:
pytest.skip("Harness not loaded")
class Runner:
def __init__(self):
self.main_attempts = 0
@@ -164,6 +194,9 @@ def test_drain_to_main_menu_uses_helper_prompt_then_returns():
def test_drain_to_main_menu_times_out_when_no_prompt_progress(monkeypatch):
if not harness:
pytest.skip("Harness not loaded")
class Runner:
def wait_for(self, pattern, timeout):
raise harness.TUIHarnessError("missing")
@@ -11,6 +11,7 @@ TEST_PATTERN = "src/tests"
RESULTS = {}
RUN_DIAGNOSTICS = []
def run_tests(run_index):
"""Run pytest and parse output for pass/fail counts."""
print(f"Run {run_index + 1}/{RUNS}...")
@@ -19,11 +20,13 @@ def run_tests(run_index):
# -q: quiet
# --no-header --no-summary: minimal output
cmd = [
sys.executable, "-m", "pytest",
sys.executable,
"-m",
"pytest",
TEST_PATTERN,
"-q",
"--no-header",
"--no-summary"
"--no-summary",
]
start_time = time.time()
@@ -33,7 +36,7 @@ def run_tests(run_index):
cmd,
capture_output=True,
text=True,
env={"PYTHONPATH": "src"} # Ensure src is in path
env={"PYTHONPATH": "src"}, # Ensure src is in path
)
output = result.stdout
exit_code = result.returncode
@@ -45,10 +48,10 @@ def run_tests(run_index):
# Parse output character by character for status
# . = pass, F = fail, E = error, s = skip, x = xfail, X = xpass
passed = output.count('.')
failed = output.count('F')
errors = output.count('E')
skipped = output.count('s')
passed = output.count(".")
failed = output.count("F")
errors = output.count("E")
skipped = output.count("s")
# Store aggregate results (naive mapping, ideally we'd parse node ids)
# Since we can't easily map node IDs without -v or --junitxml, we track totals for flakiness *rates* at suite level first.
@@ -56,20 +59,30 @@ def run_tests(run_index):
junit_path = OUTPUT_DIR / f"flaky-run-{run_index + 1}.xml"
subprocess.run(
[sys.executable, "-m", "pytest", TEST_PATTERN, f"--junitxml={junit_path}", "-q"],
[
sys.executable,
"-m",
"pytest",
TEST_PATTERN,
f"--junitxml={junit_path}",
"-q",
],
capture_output=True, # We only care about the XML file
env={"PYTHONPATH": "src"}
env={"PYTHONPATH": "src"},
)
RUN_DIAGNOSTICS.append({
RUN_DIAGNOSTICS.append(
{
"run": run_index + 1,
"code": exit_code,
"duration": duration,
"passed": passed,
"failed": failed,
"errors": errors,
"skipped": skipped
})
"skipped": skipped,
}
)
def parse_junit_xmls():
"""Parse generated JUnit XML files to detect per-test flakiness."""
@@ -108,6 +121,7 @@ def parse_junit_xmls():
return test_stats
def main():
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
@@ -129,5 +143,6 @@ def main():
print(f"Flakiness matrix written to {OUTPUT_DIR / 'flakiness-matrix.json'}")
if __name__ == "__main__":
main()
@@ -20,6 +20,7 @@ PATTERNS = [
(r"# todo", "Found '# todo' comment"),
]
def scan_file(filepath):
"""Scan a single file for suspicious patterns."""
issues = []
@@ -33,16 +34,19 @@ def scan_file(filepath):
issues.append(message)
# Check for lack of assertions (very naive)
if "test_" in filepath.name and "assert" not in content and "expect" not in content and "raise" not in content:
if (
"test_" in filepath.name
and "assert" not in content
and "expect" not in content
and "raise" not in content
):
# Exclude conftest or helpers
if "conftest" not in filepath.name and "helper" not in filepath.name:
issues.append("No obvious assertions found")
if issues:
SUSPICIOUS.append({
"file": str(filepath),
"issues": issues
})
SUSPICIOUS.append({"file": str(filepath), "issues": issues})
def main():
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
@@ -62,5 +66,6 @@ def main():
print(f"Found {len(SUSPICIOUS)} suspicious files.")
print(f"Report written to {OUTPUT_DIR / 'suspicious-tests.json'}.")
if __name__ == "__main__":
main()