feat: Add intelligent auto-router and enhanced integrations
- Add intelligent-router.sh hook for automatic agent routing - Add AUTO-TRIGGER-SUMMARY.md documentation - Add FINAL-INTEGRATION-SUMMARY.md documentation - Complete Prometheus integration (6 commands + 4 tools) - Complete Dexto integration (12 commands + 5 tools) - Enhanced Ralph with access to all agents - Fix /clawd command (removed disable-model-invocation) - Update hooks.json to v5 with intelligent routing - 291 total skills now available - All 21 commands with automatic routing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
0
prometheus/tests/docker/__init__.py
Normal file
0
prometheus/tests/docker/__init__.py
Normal file
309
prometheus/tests/docker/test_base_container.py
Normal file
309
prometheus/tests/docker/test_base_container.py
Normal file
@@ -0,0 +1,309 @@
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from unittest.mock import Mock, call, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from prometheus.docker.base_container import BaseContainer
|
||||
|
||||
|
||||
class TestContainer(BaseContainer):
|
||||
"""Concrete implementation of BaseContainer for testing."""
|
||||
|
||||
def get_dockerfile_content(self) -> str:
|
||||
return "FROM python:3.9\nWORKDIR /app\nCOPY . /app/"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temp_project_dir():
|
||||
# Create a temporary directory with some test files
|
||||
temp_dir = Path(tempfile.mkdtemp())
|
||||
test_file = temp_dir / "test.txt"
|
||||
test_file.write_text("test content")
|
||||
|
||||
yield temp_dir
|
||||
|
||||
# Cleanup
|
||||
shutil.rmtree(temp_dir)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_docker_client():
|
||||
with patch.object(BaseContainer, "client", new_callable=Mock) as mock_client:
|
||||
yield mock_client
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def container(temp_project_dir, mock_docker_client):
|
||||
container = TestContainer(
|
||||
project_path=temp_project_dir,
|
||||
workdir="/app",
|
||||
build_commands=["pip install -r requirements.txt", "python setup.py build"],
|
||||
test_commands=["pytest tests/"],
|
||||
)
|
||||
container.tag_name = "test_container_tag"
|
||||
return container
|
||||
|
||||
|
||||
def test_get_dockerfile_content(container):
|
||||
"""Test that get_dockerfile_content returns expected content"""
|
||||
dockerfile_content = container.get_dockerfile_content()
|
||||
|
||||
assert "FROM python:3.9" in dockerfile_content
|
||||
assert "WORKDIR /app" in dockerfile_content
|
||||
assert "COPY . /app/" in dockerfile_content
|
||||
|
||||
|
||||
def test_build_docker_image(container, mock_docker_client):
|
||||
"""Test building Docker image"""
|
||||
# Setup mock for api.build to return an iterable of log entries
|
||||
mock_build_logs = [
|
||||
{"stream": "Step 1/3 : FROM python:3.9"},
|
||||
{"stream": "Step 2/3 : WORKDIR /app"},
|
||||
{"stream": "Step 3/3 : COPY . /app/"},
|
||||
{"stream": "Successfully built abc123"},
|
||||
]
|
||||
mock_docker_client.api.build.return_value = iter(mock_build_logs)
|
||||
|
||||
# Execute
|
||||
container.build_docker_image()
|
||||
|
||||
# Verify
|
||||
assert (container.project_path / "prometheus.Dockerfile").exists()
|
||||
mock_docker_client.api.build.assert_called_once_with(
|
||||
path=str(container.project_path),
|
||||
dockerfile="prometheus.Dockerfile",
|
||||
tag=container.tag_name,
|
||||
rm=True,
|
||||
decode=True,
|
||||
)
|
||||
|
||||
|
||||
@patch("prometheus.docker.base_container.pexpect.spawn")
|
||||
def test_start_container(mock_spawn, container, mock_docker_client):
|
||||
"""Test starting Docker container"""
|
||||
# Setup mock for pexpect shell
|
||||
mock_shell = Mock()
|
||||
mock_spawn.return_value = mock_shell
|
||||
mock_shell.expect.return_value = 0 # Simulate successful prompt match
|
||||
|
||||
# Setup mock for docker client
|
||||
mock_containers = Mock()
|
||||
mock_docker_client.containers = mock_containers
|
||||
mock_container = Mock()
|
||||
mock_container.id = "test_container_id"
|
||||
mock_containers.run.return_value = mock_container
|
||||
|
||||
# Execute
|
||||
container.start_container()
|
||||
|
||||
# Verify docker container run was called
|
||||
mock_containers.run.assert_called_once_with(
|
||||
container.tag_name,
|
||||
detach=True,
|
||||
tty=True,
|
||||
network_mode="host",
|
||||
environment={"PYTHONPATH": f"{container.workdir}:$PYTHONPATH"},
|
||||
volumes={"/var/run/docker.sock": {"bind": "/var/run/docker.sock", "mode": "rw"}},
|
||||
)
|
||||
|
||||
# Verify pexpect shell was started
|
||||
mock_spawn.assert_called_once_with(
|
||||
f"docker exec -it {mock_container.id} /bin/bash",
|
||||
encoding="utf-8",
|
||||
timeout=container.timeout,
|
||||
)
|
||||
mock_shell.expect.assert_called()
|
||||
|
||||
|
||||
def test_is_running(container):
|
||||
"""Test is_running status check"""
|
||||
# Test when container is None
|
||||
assert not container.is_running()
|
||||
|
||||
# Test when container exists
|
||||
container.container = Mock()
|
||||
assert container.is_running()
|
||||
|
||||
|
||||
def test_update_files(container, temp_project_dir):
|
||||
"""Test updating files in container"""
|
||||
# Setup
|
||||
container.container = Mock()
|
||||
container.execute_command = Mock()
|
||||
|
||||
# Create test files
|
||||
test_file1 = temp_project_dir / "dir1" / "test1.txt"
|
||||
test_file2 = temp_project_dir / "dir2" / "test2.txt"
|
||||
test_file1.parent.mkdir(parents=True)
|
||||
test_file2.parent.mkdir(parents=True)
|
||||
test_file1.write_text("test1")
|
||||
test_file2.write_text("test2")
|
||||
|
||||
updated_files = [Path("dir1/test1.txt"), Path("dir2/test2.txt")]
|
||||
removed_files = [Path("dir3/old.txt")]
|
||||
|
||||
# Execute
|
||||
container.update_files(temp_project_dir, updated_files, removed_files)
|
||||
|
||||
# Verify
|
||||
container.execute_command.assert_has_calls(
|
||||
[call("rm dir3/old.txt"), call("mkdir -p dir1"), call("mkdir -p dir2")]
|
||||
)
|
||||
assert container.container.put_archive.called
|
||||
|
||||
|
||||
@patch("prometheus.docker.base_container.pexpect.spawn")
|
||||
def test_execute_command(mock_spawn, container):
|
||||
"""Test executing command in container using persistent shell"""
|
||||
# Setup mock shell
|
||||
mock_shell = Mock()
|
||||
mock_spawn.return_value = mock_shell
|
||||
|
||||
# Setup container and shell
|
||||
container.container = Mock()
|
||||
container.container.id = "test_container_id"
|
||||
container.shell = mock_shell
|
||||
mock_shell.isalive.return_value = True
|
||||
|
||||
# Mock the shell interactions
|
||||
mock_shell.match = Mock()
|
||||
mock_shell.match.group.return_value = "0" # Exit code 0
|
||||
mock_shell.before = "test command\ncommand output"
|
||||
|
||||
# Execute
|
||||
result = container.execute_command("test command")
|
||||
|
||||
# Verify shell interactions
|
||||
assert mock_shell.sendline.call_count == 2 # Command + marker command
|
||||
mock_shell.expect.assert_called()
|
||||
|
||||
# The result should contain the cleaned output
|
||||
assert "command output" in result
|
||||
|
||||
|
||||
def test_execute_command_with_mock(container):
|
||||
"""Test executing command with direct mocking"""
|
||||
# Setup - directly mock the execute_command method
|
||||
container.execute_command = Mock(return_value="mocked output")
|
||||
container.container = Mock()
|
||||
|
||||
# Execute
|
||||
result = container.execute_command("test command")
|
||||
|
||||
# Verify
|
||||
container.execute_command.assert_called_once_with("test command")
|
||||
assert result == "mocked output"
|
||||
|
||||
|
||||
def test_reset_repository(container):
|
||||
"""Test container reset repository"""
|
||||
# Setup - Mock the execute_command method
|
||||
container.execute_command = Mock(return_value="Command output")
|
||||
container.container = Mock()
|
||||
|
||||
# Execute
|
||||
container.reset_repository()
|
||||
|
||||
# Verify - Check that execute_command was called twice with the correct commands
|
||||
assert container.execute_command.call_count == 2
|
||||
expected_calls = [call("git reset --hard"), call("git clean -fd")]
|
||||
container.execute_command.assert_has_calls(expected_calls, any_order=False)
|
||||
|
||||
|
||||
@patch("prometheus.docker.base_container.pexpect.spawn")
|
||||
def test_cleanup(mock_spawn, container, mock_docker_client):
|
||||
"""Test cleanup of container resources"""
|
||||
# Setup
|
||||
mock_container = Mock()
|
||||
container.container = mock_container
|
||||
|
||||
# Setup mock shell
|
||||
mock_shell = Mock()
|
||||
mock_shell.isalive.return_value = True
|
||||
container.shell = mock_shell
|
||||
|
||||
# Execute
|
||||
container.cleanup()
|
||||
|
||||
# Verify shell cleanup
|
||||
mock_shell.close.assert_called_once_with(force=True)
|
||||
|
||||
# Verify container cleanup
|
||||
mock_container.stop.assert_called_once_with(timeout=10)
|
||||
mock_container.remove.assert_called_once_with(force=True)
|
||||
mock_docker_client.images.remove.assert_called_once_with(container.tag_name, force=True)
|
||||
assert not container.project_path.exists()
|
||||
|
||||
|
||||
def test_run_build(container):
|
||||
"""Test that build commands are executed correctly"""
|
||||
container.execute_command = Mock()
|
||||
container.execute_command.side_effect = ["Output 1", "Output 2"]
|
||||
|
||||
build_output = container.run_build()
|
||||
|
||||
# Verify execute_command was called for each build command
|
||||
assert container.execute_command.call_count == 2
|
||||
container.execute_command.assert_any_call("pip install -r requirements.txt")
|
||||
container.execute_command.assert_any_call("python setup.py build")
|
||||
|
||||
# Verify output format
|
||||
expected_output = (
|
||||
"$ pip install -r requirements.txt\nOutput 1\n$ python setup.py build\nOutput 2\n"
|
||||
)
|
||||
assert build_output == expected_output
|
||||
|
||||
|
||||
def test_run_test(container):
|
||||
"""Test that test commands are executed correctly"""
|
||||
container.execute_command = Mock()
|
||||
container.execute_command.return_value = "Test passed"
|
||||
|
||||
test_output = container.run_test()
|
||||
|
||||
# Verify execute_command was called for the test command
|
||||
container.execute_command.assert_called_once_with("pytest tests/")
|
||||
|
||||
# Verify output format
|
||||
expected_output = "$ pytest tests/\nTest passed\n"
|
||||
assert test_output == expected_output
|
||||
|
||||
|
||||
def test_run_build_no_commands(container):
|
||||
"""Test run_build when no build commands are defined"""
|
||||
container.build_commands = None
|
||||
result = container.run_build()
|
||||
assert result == ""
|
||||
|
||||
|
||||
def test_run_test_no_commands(container):
|
||||
"""Test run_test when no test commands are defined"""
|
||||
container.test_commands = None
|
||||
result = container.run_test()
|
||||
assert result == ""
|
||||
|
||||
|
||||
@patch("prometheus.docker.base_container.pexpect.spawn")
|
||||
def test_restart_shell_if_needed(mock_spawn, container):
|
||||
"""Test shell restart functionality"""
|
||||
# Setup
|
||||
mock_shell_dead = Mock()
|
||||
mock_shell_dead.isalive.return_value = False
|
||||
|
||||
mock_shell_new = Mock()
|
||||
mock_shell_new.expect.return_value = 0
|
||||
mock_spawn.return_value = mock_shell_new
|
||||
|
||||
container.container = Mock()
|
||||
container.container.id = "test_container_id"
|
||||
container.shell = mock_shell_dead
|
||||
|
||||
# Execute
|
||||
container._restart_shell_if_needed()
|
||||
|
||||
# Verify old shell was closed and new one started
|
||||
mock_shell_dead.close.assert_called_once_with(force=True)
|
||||
mock_spawn.assert_called_once()
|
||||
assert container.shell == mock_shell_new
|
||||
44
prometheus/tests/docker/test_general_container.py
Normal file
44
prometheus/tests/docker/test_general_container.py
Normal file
@@ -0,0 +1,44 @@
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from prometheus.docker.general_container import GeneralContainer
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temp_project_dir():
|
||||
# Create a temporary directory with some test files
|
||||
temp_dir = Path(tempfile.mkdtemp())
|
||||
test_file = temp_dir / "test.txt"
|
||||
test_file.write_text("test content")
|
||||
|
||||
yield temp_dir
|
||||
|
||||
# Cleanup
|
||||
shutil.rmtree(temp_dir)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def container(temp_project_dir):
|
||||
return GeneralContainer(temp_project_dir)
|
||||
|
||||
|
||||
def test_initialization(container, temp_project_dir):
|
||||
"""Test that the container is initialized correctly"""
|
||||
assert isinstance(container.tag_name, str)
|
||||
assert container.tag_name.startswith("prometheus_general_container_")
|
||||
assert container.project_path != temp_project_dir
|
||||
assert (container.project_path / "test.txt").exists()
|
||||
|
||||
|
||||
def test_get_dockerfile_content(container):
|
||||
dockerfile_content = container.get_dockerfile_content()
|
||||
|
||||
assert dockerfile_content
|
||||
|
||||
assert "FROM ubuntu:24.04" in dockerfile_content
|
||||
assert "WORKDIR /app" in dockerfile_content
|
||||
assert "RUN apt-get update" in dockerfile_content
|
||||
assert "COPY . /app/" in dockerfile_content
|
||||
51
prometheus/tests/docker/test_user_defined_container.py
Normal file
51
prometheus/tests/docker/test_user_defined_container.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from prometheus.docker.user_defined_container import UserDefinedContainer
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temp_project_dir():
|
||||
# Create a temporary directory with some test files
|
||||
temp_dir = Path(tempfile.mkdtemp())
|
||||
test_file = temp_dir / "test.txt"
|
||||
test_file.write_text("test content")
|
||||
|
||||
yield temp_dir
|
||||
|
||||
# Cleanup
|
||||
shutil.rmtree(temp_dir)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def container(temp_project_dir):
|
||||
return UserDefinedContainer(
|
||||
temp_project_dir,
|
||||
"/app",
|
||||
"FROM python:3.9\nWORKDIR /app\nCOPY . /app/",
|
||||
None,
|
||||
["pip install -r requirements.txt", "python setup.py build"],
|
||||
["pytest tests/"],
|
||||
)
|
||||
|
||||
|
||||
def test_initialization(container, temp_project_dir):
|
||||
"""Test that the container is initialized correctly"""
|
||||
assert isinstance(container.tag_name, str)
|
||||
assert container.tag_name.startswith("prometheus_user_defined_container_")
|
||||
assert container.project_path != temp_project_dir
|
||||
assert (container.project_path / "test.txt").exists()
|
||||
|
||||
|
||||
def test_get_dockerfile_content(container):
|
||||
dockerfile_content = container.get_dockerfile_content()
|
||||
|
||||
assert dockerfile_content
|
||||
|
||||
# Check for key elements in the Dockerfile
|
||||
assert "FROM python:3.9" in dockerfile_content
|
||||
assert "WORKDIR /app" in dockerfile_content
|
||||
assert "COPY . /app/" in dockerfile_content
|
||||
Reference in New Issue
Block a user