From 7e169af261294bf6774cd82cd30bb26ce68d609c Mon Sep 17 00:00:00 2001 From: danielmeppiel Date: Sat, 14 Mar 2026 12:14:15 +0100 Subject: [PATCH] fix(test): handle Windows file locking in integration test teardown On Windows, recently-terminated subprocesses may still hold file locks on temp directories (WinError 32). Fix test_auto_install_e2e.py by: - Using shutil.rmtree(ignore_errors=True) in teardown_method - Closing subprocess stdout pipes before waiting - Increasing wait timeout for graceful shutdown Also fix test_ado_e2e.py venv path fallback for Windows (.venv/Scripts vs .venv/bin). Ref #185 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/integration/test_ado_e2e.py | 6 +++++- tests/integration/test_auto_install_e2e.py | 23 +++++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/tests/integration/test_ado_e2e.py b/tests/integration/test_ado_e2e.py index e007a5a8..5013fcf1 100644 --- a/tests/integration/test_ado_e2e.py +++ b/tests/integration/test_ado_e2e.py @@ -10,6 +10,7 @@ import os import shutil import subprocess +import sys import tempfile from pathlib import Path @@ -31,7 +32,10 @@ def run_apm_command(cmd: str, cwd: Path, timeout: int = 60) -> subprocess.Comple apm_path = apm_on_path else: # Fallback to local dev venv - apm_path = Path(__file__).parent.parent.parent / ".venv" / "bin" / "apm" + if sys.platform == "win32": + apm_path = Path(__file__).parent.parent.parent / ".venv" / "Scripts" / "apm.exe" + else: + apm_path = Path(__file__).parent.parent.parent / ".venv" / "bin" / "apm" full_cmd = f"{apm_path} {cmd}" result = subprocess.run( diff --git a/tests/integration/test_auto_install_e2e.py b/tests/integration/test_auto_install_e2e.py index 8a014d5e..33b9a468 100644 --- a/tests/integration/test_auto_install_e2e.py +++ b/tests/integration/test_auto_install_e2e.py @@ -69,7 +69,10 @@ def teardown_method(self): """Clean up test environment.""" os.chdir(self.original_dir) if os.path.exists(self.test_dir): - shutil.rmtree(self.test_dir) + # ignore_errors=True: on Windows, recently-terminated subprocesses + # may still hold file locks on the temp directory (WinError 32). + # CI temp dirs are ephemeral — safe to leave behind if needed. + shutil.rmtree(self.test_dir, ignore_errors=True) def test_auto_install_virtual_prompt_first_run(self, temp_e2e_home): """Test auto-install on first run with virtual package reference. @@ -126,8 +129,9 @@ def test_auto_install_virtual_prompt_first_run(self, temp_e2e_home): break # Wait for graceful shutdown + process.stdout.close() try: - process.wait(timeout=5) + process.wait(timeout=10) except subprocess.TimeoutExpired: process.kill() process.wait() @@ -185,7 +189,8 @@ def test_auto_install_uses_cache_on_second_run(self, temp_e2e_home): if "Package installed and ready to run" in line: process.terminate() break - process.wait(timeout=5) + process.stdout.close() + process.wait(timeout=10) except: process.kill() process.wait() @@ -218,7 +223,8 @@ def test_auto_install_uses_cache_on_second_run(self, temp_e2e_home): if "Executing" in line or "Package installed and ready to run" in line: process.terminate() break - process.wait(timeout=5) + process.stdout.close() + process.wait(timeout=10) except: process.kill() process.wait() @@ -265,7 +271,8 @@ def test_simple_name_works_after_install(self, temp_e2e_home): if "Package installed and ready to run" in line: process.terminate() break - process.wait(timeout=5) + process.stdout.close() + process.wait(timeout=10) except: process.kill() process.wait() @@ -294,7 +301,8 @@ def test_simple_name_works_after_install(self, temp_e2e_home): if "Executing" in line or "Auto-discovered" in line: process.terminate() break - process.wait(timeout=5) + process.stdout.close() + process.wait(timeout=10) except: process.kill() process.wait() @@ -340,7 +348,8 @@ def test_auto_install_with_qualified_path(self, temp_e2e_home): if "Package installed and ready to run" in line: process.terminate() break - process.wait(timeout=5) + process.stdout.close() + process.wait(timeout=10) except: process.kill() process.wait()