Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions tests/integration/test_auto_install_e2e.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ def test_auto_install_virtual_prompt_first_run(self, temp_e2e_home):

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

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

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

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

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

def test_auto_install_uses_cache_on_second_run(self, temp_e2e_home):
"""Test that second run uses cached package (no re-download).
Expand Down Expand Up @@ -182,7 +182,7 @@ def test_auto_install_uses_cache_on_second_run(self, temp_e2e_home):
for line in iter(process.stdout.readline, ''):
if not line:
break
if "Package installed and ready to run" in line:
if "Package installed and ready to run" in line:
process.terminate()
break
process.wait(timeout=5)
Expand Down Expand Up @@ -215,7 +215,7 @@ def test_auto_install_uses_cache_on_second_run(self, temp_e2e_home):
break
output_lines.append(line)
# Terminate once we see execution starting (no need for full run)
if "Executing" in line or "" in line:
if "Executing" in line or "Package installed and ready to run" in line:
process.terminate()
break
process.wait(timeout=5)
Expand All @@ -227,10 +227,10 @@ def test_auto_install_uses_cache_on_second_run(self, temp_e2e_home):

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

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

def test_simple_name_works_after_install(self, temp_e2e_home):
"""Test that simple name works after package is installed.
Expand Down Expand Up @@ -262,7 +262,7 @@ def test_simple_name_works_after_install(self, temp_e2e_home):
for line in iter(process.stdout.readline, ''):
if not line:
break
if "Package installed and ready to run" in line:
if "Package installed and ready to run" in line:
process.terminate()
break
process.wait(timeout=5)
Expand Down Expand Up @@ -302,10 +302,10 @@ def test_simple_name_works_after_install(self, temp_e2e_home):
output = ''.join(output_lines)

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

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

def test_auto_install_with_qualified_path(self, temp_e2e_home):
"""Test auto-install works with qualified path format.
Expand Down Expand Up @@ -337,7 +337,7 @@ def test_auto_install_with_qualified_path(self, temp_e2e_home):
if not line:
break
# Terminate once installation completes
if "Package installed and ready to run" in line:
if "Package installed and ready to run" in line:
process.terminate()
break
process.wait(timeout=5)
Expand All @@ -353,7 +353,7 @@ def test_auto_install_with_qualified_path(self, temp_e2e_home):
skill_file = package_path / "SKILL.md"
assert skill_file.exists(), "SKILL.md should exist"

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


if __name__ == "__main__":
Expand Down
44 changes: 24 additions & 20 deletions tests/unit/test_install_command.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Tests for the apm install command auto-bootstrap feature."""

import contextlib
import pytest
import tempfile
import os
Expand Down Expand Up @@ -31,11 +32,24 @@ def teardown_method(self):
repo_root = Path(__file__).parent.parent.parent
os.chdir(str(repo_root))

def test_install_no_apm_yml_no_packages_shows_helpful_error(self):
"""Test that install without apm.yml and without packages shows helpful error."""
@contextlib.contextmanager
def _chdir_tmp(self):
"""Context manager: create a temp dir, chdir into it, restore CWD on exit.

Restoring CWD *before* TemporaryDirectory.__exit__ avoids
PermissionError [WinError 32] on Windows when the process's current
directory is inside the directory being deleted.
"""
with tempfile.TemporaryDirectory() as tmp_dir:
os.chdir(tmp_dir)
try:
os.chdir(tmp_dir)
yield Path(tmp_dir)
finally:
os.chdir(self.original_dir)
Comment thread
sergio-sisternes-epam marked this conversation as resolved.

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

assert result.exit_code == 1
Expand All @@ -51,9 +65,7 @@ def test_install_no_apm_yml_with_packages_creates_minimal_apm_yml(
self, mock_install_apm, mock_apm_package, mock_validate, monkeypatch
):
"""Test that install with packages but no apm.yml creates minimal apm.yml."""
with tempfile.TemporaryDirectory() as tmp_dir:
os.chdir(tmp_dir)

with self._chdir_tmp():
# Mock package validation to return True
mock_validate.return_value = True

Expand Down Expand Up @@ -91,9 +103,7 @@ def test_install_no_apm_yml_with_multiple_packages(
self, mock_install_apm, mock_apm_package, mock_validate, monkeypatch
):
"""Test that install with multiple packages creates apm.yml and adds all."""
with tempfile.TemporaryDirectory() as tmp_dir:
os.chdir(tmp_dir)

with self._chdir_tmp():
# Mock package validation
mock_validate.return_value = True

Expand Down Expand Up @@ -127,9 +137,7 @@ def test_install_existing_apm_yml_preserves_behavior(
self, mock_install_apm, mock_apm_package
):
"""Test that install with existing apm.yml works as before."""
with tempfile.TemporaryDirectory() as tmp_dir:
os.chdir(tmp_dir)

with self._chdir_tmp():
# Create existing apm.yml
existing_config = {
"name": "test-project",
Expand Down Expand Up @@ -170,9 +178,9 @@ def test_install_auto_created_apm_yml_has_correct_metadata(
self, mock_install_apm, mock_apm_package, mock_validate
):
"""Test that auto-created apm.yml has correct metadata."""
with tempfile.TemporaryDirectory() as tmp_dir:
with self._chdir_tmp() as tmp_dir:
# Create a directory with a specific name to test project name detection
project_dir = Path(tmp_dir) / "my-awesome-project"
project_dir = tmp_dir / "my-awesome-project"
project_dir.mkdir()
os.chdir(project_dir)

Expand Down Expand Up @@ -204,9 +212,7 @@ def test_install_auto_created_apm_yml_has_correct_metadata(
@patch("apm_cli.commands.install._validate_package_exists")
def test_install_invalid_package_format_with_no_apm_yml(self, mock_validate):
"""Test that invalid package format fails gracefully even with auto-bootstrap."""
with tempfile.TemporaryDirectory() as tmp_dir:
os.chdir(tmp_dir)

with self._chdir_tmp():
# Don't mock validation - let it handle invalid format
result = self.runner.invoke(cli, ["install", "invalid-package"])

Expand All @@ -222,9 +228,7 @@ def test_install_dry_run_with_no_apm_yml_shows_what_would_be_created(
self, mock_install_apm, mock_apm_package, mock_validate
):
"""Test that dry-run with no apm.yml shows what would be created."""
with tempfile.TemporaryDirectory() as tmp_dir:
os.chdir(tmp_dir)

with self._chdir_tmp():
mock_validate.return_value = True

mock_pkg_instance = MagicMock()
Expand Down
Loading