Skip to content

Commit a000d35

Browse files
Merge pull request #281 from sergio-sisternes-epam/fix/windows-ci-tempdir-cleanup
fix: restore CWD before TemporaryDirectory cleanup on Windows
2 parents 0f6c179 + 13c9c8c commit a000d35

2 files changed

Lines changed: 39 additions & 35 deletions

File tree

tests/integration/test_auto_install_e2e.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ def test_auto_install_virtual_prompt_first_run(self, temp_e2e_home):
119119

120120
# Once we see "Package installed and ready to run", execution is about to start
121121
# Terminate to avoid waiting for full prompt execution
122-
if "Package installed and ready to run" in line:
122+
if "Package installed and ready to run" in line:
123123
execution_started = True
124-
print("\n Test validated - terminating to save time")
124+
print("\n Test validated - terminating to save time")
125125
process.terminate()
126126
break
127127

@@ -136,11 +136,11 @@ def test_auto_install_virtual_prompt_first_run(self, temp_e2e_home):
136136
output = ''.join(output_lines)
137137

138138
# Check output for auto-install messages
139-
assert "Auto-installing virtual package" in output or "📦" in output, \
139+
assert "Auto-installing virtual package" in output or "[+]" in output, \
140140
"Should show auto-install message"
141-
assert "Downloading from" in output or "📥" in output, \
141+
assert "Downloading from" in output or "[>]" in output, \
142142
"Should show download message"
143-
assert execution_started, "Should have started execution (Package installed and ready to run)"
143+
assert execution_started, "Should have started execution (Package installed and ready to run)"
144144

145145
# Verify package was installed
146146
package_path = apm_modules / "github" / "awesome-copilot" / "skills" / "architecture-blueprint-generator"
@@ -150,7 +150,7 @@ def test_auto_install_virtual_prompt_first_run(self, temp_e2e_home):
150150
assert (package_path / "SKILL.md").exists() or (package_path / "apm.yml").exists(), \
151151
"Virtual package should have SKILL.md or apm.yml"
152152

153-
print(f" Auto-install successful: {package_path}")
153+
print(f"[+] Auto-install successful: {package_path}")
154154

155155
def test_auto_install_uses_cache_on_second_run(self, temp_e2e_home):
156156
"""Test that second run uses cached package (no re-download).
@@ -182,7 +182,7 @@ def test_auto_install_uses_cache_on_second_run(self, temp_e2e_home):
182182
for line in iter(process.stdout.readline, ''):
183183
if not line:
184184
break
185-
if "Package installed and ready to run" in line:
185+
if "Package installed and ready to run" in line:
186186
process.terminate()
187187
break
188188
process.wait(timeout=5)
@@ -215,7 +215,7 @@ def test_auto_install_uses_cache_on_second_run(self, temp_e2e_home):
215215
break
216216
output_lines.append(line)
217217
# Terminate once we see execution starting (no need for full run)
218-
if "Executing" in line or "" in line:
218+
if "Executing" in line or "Package installed and ready to run" in line:
219219
process.terminate()
220220
break
221221
process.wait(timeout=5)
@@ -227,10 +227,10 @@ def test_auto_install_uses_cache_on_second_run(self, temp_e2e_home):
227227

228228
# Check output - should NOT show install/download messages
229229
assert "Auto-installing" not in output, "Should not auto-install on second run"
230-
assert "Auto-discovered" in output or "" in output, \
230+
assert "Auto-discovered" in output or "[i]" in output, \
231231
"Should show auto-discovery message (using cached package)"
232232

233-
print(" Second run used cached package (no re-download)")
233+
print("[+] Second run used cached package (no re-download)")
234234

235235
def test_simple_name_works_after_install(self, temp_e2e_home):
236236
"""Test that simple name works after package is installed.
@@ -262,7 +262,7 @@ def test_simple_name_works_after_install(self, temp_e2e_home):
262262
for line in iter(process.stdout.readline, ''):
263263
if not line:
264264
break
265-
if "Package installed and ready to run" in line:
265+
if "Package installed and ready to run" in line:
266266
process.terminate()
267267
break
268268
process.wait(timeout=5)
@@ -302,10 +302,10 @@ def test_simple_name_works_after_install(self, temp_e2e_home):
302302
output = ''.join(output_lines)
303303

304304
# Check output - should discover the installed prompt
305-
assert "Auto-discovered" in output or "" in output, \
305+
assert "Auto-discovered" in output or "[i]" in output, \
306306
"Should auto-discover prompt from installed package"
307307

308-
print(" Simple name works after installation")
308+
print("[+] Simple name works after installation")
309309

310310
def test_auto_install_with_qualified_path(self, temp_e2e_home):
311311
"""Test auto-install works with qualified path format.
@@ -337,7 +337,7 @@ def test_auto_install_with_qualified_path(self, temp_e2e_home):
337337
if not line:
338338
break
339339
# Terminate once installation completes
340-
if "Package installed and ready to run" in line:
340+
if "Package installed and ready to run" in line:
341341
process.terminate()
342342
break
343343
process.wait(timeout=5)
@@ -353,7 +353,7 @@ def test_auto_install_with_qualified_path(self, temp_e2e_home):
353353
skill_file = package_path / "SKILL.md"
354354
assert skill_file.exists(), "SKILL.md should exist"
355355

356-
print(" Auto-install works with qualified path")
356+
print("[+] Auto-install works with qualified path")
357357

358358

359359
if __name__ == "__main__":

tests/unit/test_install_command.py

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Tests for the apm install command auto-bootstrap feature."""
22

3+
import contextlib
34
import pytest
45
import tempfile
56
import os
@@ -31,11 +32,24 @@ def teardown_method(self):
3132
repo_root = Path(__file__).parent.parent.parent
3233
os.chdir(str(repo_root))
3334

34-
def test_install_no_apm_yml_no_packages_shows_helpful_error(self):
35-
"""Test that install without apm.yml and without packages shows helpful error."""
35+
@contextlib.contextmanager
36+
def _chdir_tmp(self):
37+
"""Context manager: create a temp dir, chdir into it, restore CWD on exit.
38+
39+
Restoring CWD *before* TemporaryDirectory.__exit__ avoids
40+
PermissionError [WinError 32] on Windows when the process's current
41+
directory is inside the directory being deleted.
42+
"""
3643
with tempfile.TemporaryDirectory() as tmp_dir:
37-
os.chdir(tmp_dir)
44+
try:
45+
os.chdir(tmp_dir)
46+
yield Path(tmp_dir)
47+
finally:
48+
os.chdir(self.original_dir)
3849

50+
def test_install_no_apm_yml_no_packages_shows_helpful_error(self):
51+
"""Test that install without apm.yml and without packages shows helpful error."""
52+
with self._chdir_tmp():
3953
result = self.runner.invoke(cli, ["install"])
4054

4155
assert result.exit_code == 1
@@ -51,9 +65,7 @@ def test_install_no_apm_yml_with_packages_creates_minimal_apm_yml(
5165
self, mock_install_apm, mock_apm_package, mock_validate, monkeypatch
5266
):
5367
"""Test that install with packages but no apm.yml creates minimal apm.yml."""
54-
with tempfile.TemporaryDirectory() as tmp_dir:
55-
os.chdir(tmp_dir)
56-
68+
with self._chdir_tmp():
5769
# Mock package validation to return True
5870
mock_validate.return_value = True
5971

@@ -91,9 +103,7 @@ def test_install_no_apm_yml_with_multiple_packages(
91103
self, mock_install_apm, mock_apm_package, mock_validate, monkeypatch
92104
):
93105
"""Test that install with multiple packages creates apm.yml and adds all."""
94-
with tempfile.TemporaryDirectory() as tmp_dir:
95-
os.chdir(tmp_dir)
96-
106+
with self._chdir_tmp():
97107
# Mock package validation
98108
mock_validate.return_value = True
99109

@@ -127,9 +137,7 @@ def test_install_existing_apm_yml_preserves_behavior(
127137
self, mock_install_apm, mock_apm_package
128138
):
129139
"""Test that install with existing apm.yml works as before."""
130-
with tempfile.TemporaryDirectory() as tmp_dir:
131-
os.chdir(tmp_dir)
132-
140+
with self._chdir_tmp():
133141
# Create existing apm.yml
134142
existing_config = {
135143
"name": "test-project",
@@ -170,9 +178,9 @@ def test_install_auto_created_apm_yml_has_correct_metadata(
170178
self, mock_install_apm, mock_apm_package, mock_validate
171179
):
172180
"""Test that auto-created apm.yml has correct metadata."""
173-
with tempfile.TemporaryDirectory() as tmp_dir:
181+
with self._chdir_tmp() as tmp_dir:
174182
# Create a directory with a specific name to test project name detection
175-
project_dir = Path(tmp_dir) / "my-awesome-project"
183+
project_dir = tmp_dir / "my-awesome-project"
176184
project_dir.mkdir()
177185
os.chdir(project_dir)
178186

@@ -204,9 +212,7 @@ def test_install_auto_created_apm_yml_has_correct_metadata(
204212
@patch("apm_cli.commands.install._validate_package_exists")
205213
def test_install_invalid_package_format_with_no_apm_yml(self, mock_validate):
206214
"""Test that invalid package format fails gracefully even with auto-bootstrap."""
207-
with tempfile.TemporaryDirectory() as tmp_dir:
208-
os.chdir(tmp_dir)
209-
215+
with self._chdir_tmp():
210216
# Don't mock validation - let it handle invalid format
211217
result = self.runner.invoke(cli, ["install", "invalid-package"])
212218

@@ -222,9 +228,7 @@ def test_install_dry_run_with_no_apm_yml_shows_what_would_be_created(
222228
self, mock_install_apm, mock_apm_package, mock_validate
223229
):
224230
"""Test that dry-run with no apm.yml shows what would be created."""
225-
with tempfile.TemporaryDirectory() as tmp_dir:
226-
os.chdir(tmp_dir)
227-
231+
with self._chdir_tmp():
228232
mock_validate.return_value = True
229233

230234
mock_pkg_instance = MagicMock()

0 commit comments

Comments
 (0)