superclaude-org--superclaude_framework
d59f22770e
The new test_mcp_list test (added in this PR) exposed a latent bug: check_mcp_server_installed() spawns 'claude mcp list' but only caught TimeoutExpired/SubprocessError, not FileNotFoundError. On machines without the claude CLI (e.g. CI) the call raised FileNotFoundError and crashed 'superclaude mcp --list'. Add FileNotFoundError to the except, matching the pattern already used by check_docker_available() and the prerequisite checks in this file. Also apply ruff format to files this PR introduced/modified: confidence.py, test_cli_e2e.py, test_execution_init.py. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
328 行
11 KiB
Python
328 行
11 KiB
Python
"""
|
|
Tests for Execution Module Init
|
|
|
|
Tests intelligent_execute, quick_execute, and safe_execute functions.
|
|
"""
|
|
|
|
import tempfile
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
from superclaude.execution import (
|
|
ConfidenceScore,
|
|
ReflectionEngine,
|
|
intelligent_execute,
|
|
quick_execute,
|
|
safe_execute,
|
|
should_parallelize,
|
|
)
|
|
|
|
|
|
class TestExports:
|
|
"""Tests for module exports"""
|
|
|
|
def test_all_exports_available(self):
|
|
"""Test all __all__ exports are importable"""
|
|
from superclaude import execution
|
|
|
|
assert hasattr(execution, "intelligent_execute")
|
|
assert hasattr(execution, "ReflectionEngine")
|
|
assert hasattr(execution, "ParallelExecutor")
|
|
assert hasattr(execution, "SelfCorrectionEngine")
|
|
assert hasattr(execution, "ConfidenceScore")
|
|
assert hasattr(execution, "ExecutionPlan")
|
|
assert hasattr(execution, "RootCause")
|
|
assert hasattr(execution, "Task")
|
|
assert hasattr(execution, "should_parallelize")
|
|
assert hasattr(execution, "reflect_before_execution")
|
|
assert hasattr(execution, "learn_from_failure")
|
|
|
|
|
|
class TestIntelligentExecute:
|
|
"""Tests for intelligent_execute function"""
|
|
|
|
def test_basic_execution(self):
|
|
"""Test basic execution with simple operations"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
operations = [
|
|
lambda: "result1",
|
|
lambda: "result2",
|
|
]
|
|
|
|
result = intelligent_execute(
|
|
task="Create a simple test function in utils.py",
|
|
operations=operations,
|
|
repo_path=Path(tmpdir),
|
|
)
|
|
|
|
assert result["status"] in ["success", "partial_failure", "blocked"]
|
|
|
|
def test_execution_with_context(self):
|
|
"""Test execution with context"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
# Create PROJECT_INDEX.md for better confidence
|
|
(Path(tmpdir) / "PROJECT_INDEX.md").write_text("# Index")
|
|
|
|
context = {
|
|
"project_index": "loaded",
|
|
"current_branch": "main",
|
|
"git_status": "clean",
|
|
}
|
|
|
|
operations = [lambda: "done"]
|
|
|
|
result = intelligent_execute(
|
|
task="Add validation function to utils.py",
|
|
operations=operations,
|
|
context=context,
|
|
repo_path=Path(tmpdir),
|
|
)
|
|
|
|
assert "confidence" in result
|
|
|
|
def test_execution_blocked_low_confidence(self):
|
|
"""Test execution blocked when confidence is low"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
# Vague task should have low clarity
|
|
result = intelligent_execute(
|
|
task="improve", # Very vague
|
|
operations=[lambda: "x"],
|
|
repo_path=Path(tmpdir),
|
|
)
|
|
|
|
# May be blocked or proceed depending on other factors
|
|
assert result["status"] in ["blocked", "success", "partial_failure"]
|
|
|
|
def test_execution_with_failing_operation(self):
|
|
"""Test execution with operation that returns None"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
# Create good context
|
|
(Path(tmpdir) / "PROJECT_INDEX.md").write_text("# Index")
|
|
|
|
context = {
|
|
"project_index": "loaded",
|
|
"current_branch": "main",
|
|
"git_status": "clean",
|
|
}
|
|
|
|
operations = [
|
|
lambda: "success",
|
|
lambda: None, # Failure
|
|
]
|
|
|
|
result = intelligent_execute(
|
|
task="Create test function with validation in module.py",
|
|
operations=operations,
|
|
context=context,
|
|
repo_path=Path(tmpdir),
|
|
auto_correct=True,
|
|
)
|
|
|
|
# Should have at least one failure
|
|
if result["status"] != "blocked":
|
|
assert result["status"] in ["success", "partial_failure"]
|
|
|
|
def test_execution_with_exception(self):
|
|
"""Test execution handles exceptions"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
(Path(tmpdir) / "PROJECT_INDEX.md").write_text("# Index")
|
|
|
|
context = {
|
|
"project_index": "loaded",
|
|
"current_branch": "main",
|
|
"git_status": "clean",
|
|
}
|
|
|
|
def failing_op():
|
|
raise ValueError("Test exception")
|
|
|
|
operations = [failing_op]
|
|
|
|
result = intelligent_execute(
|
|
task="Create validation function in utils.py module",
|
|
operations=operations,
|
|
context=context,
|
|
repo_path=Path(tmpdir),
|
|
auto_correct=True,
|
|
)
|
|
|
|
# May be blocked before reaching exception, fail, or partial_failure
|
|
# (parallel executor catches exceptions per-task)
|
|
assert result["status"] in [
|
|
"blocked",
|
|
"failed",
|
|
"partial_failure",
|
|
"success",
|
|
]
|
|
|
|
def test_execution_without_auto_correct(self):
|
|
"""Test execution with auto_correct disabled"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
(Path(tmpdir) / "PROJECT_INDEX.md").write_text("# Index")
|
|
|
|
context = {
|
|
"project_index": "loaded",
|
|
"current_branch": "main",
|
|
"git_status": "clean",
|
|
}
|
|
|
|
operations = [lambda: None]
|
|
|
|
result = intelligent_execute(
|
|
task="Add function to module.py file",
|
|
operations=operations,
|
|
context=context,
|
|
repo_path=Path(tmpdir),
|
|
auto_correct=False,
|
|
)
|
|
|
|
assert result["status"] in ["blocked", "success", "partial_failure"]
|
|
|
|
|
|
class TestQuickExecute:
|
|
"""Tests for quick_execute function"""
|
|
|
|
def test_quick_execute_single(self):
|
|
"""Test quick execution with single operation"""
|
|
operations = [lambda: "result"]
|
|
|
|
results = quick_execute(operations)
|
|
|
|
assert len(results) == 1
|
|
assert results[0] == "result"
|
|
|
|
def test_quick_execute_multiple(self):
|
|
"""Test quick execution with multiple operations"""
|
|
operations = [
|
|
lambda: "a",
|
|
lambda: "b",
|
|
lambda: "c",
|
|
]
|
|
|
|
results = quick_execute(operations)
|
|
|
|
assert len(results) == 3
|
|
assert set(results) == {"a", "b", "c"}
|
|
|
|
def test_quick_execute_returns_list(self):
|
|
"""Test quick execution returns a list"""
|
|
operations = [lambda: 42]
|
|
results = quick_execute(operations)
|
|
|
|
assert isinstance(results, list)
|
|
assert len(results) == 1
|
|
|
|
|
|
class TestSafeExecute:
|
|
"""Tests for safe_execute function"""
|
|
|
|
def test_safe_execute_success(self):
|
|
"""Test safe execution with successful operation"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
# Create good context
|
|
(Path(tmpdir) / "PROJECT_INDEX.md").write_text("# Index")
|
|
|
|
# Patch to ensure high confidence
|
|
with patch.object(ReflectionEngine, "reflect") as mock_reflect:
|
|
# Create high confidence result
|
|
from superclaude.execution.reflection import ReflectionResult
|
|
|
|
clarity = ReflectionResult("Clarity", 0.9, [], [])
|
|
mistakes = ReflectionResult("Mistakes", 1.0, [], [])
|
|
context_ready = ReflectionResult("Context", 0.8, [], [])
|
|
|
|
mock_reflect.return_value = ConfidenceScore(
|
|
requirement_clarity=clarity,
|
|
mistake_check=mistakes,
|
|
context_ready=context_ready,
|
|
confidence=0.9,
|
|
should_proceed=True,
|
|
blockers=[],
|
|
recommendations=[],
|
|
)
|
|
|
|
# This may still fail due to implementation details
|
|
try:
|
|
result = safe_execute(
|
|
task="Create validation function",
|
|
operation=lambda: "success",
|
|
)
|
|
assert result == "success"
|
|
except RuntimeError:
|
|
# Blocked or failed is also valid outcome
|
|
pass
|
|
|
|
def test_safe_execute_blocked_raises(self):
|
|
"""Test safe execution raises when blocked"""
|
|
with tempfile.TemporaryDirectory():
|
|
with patch.object(ReflectionEngine, "reflect") as mock_reflect:
|
|
from superclaude.execution.reflection import ReflectionResult
|
|
|
|
clarity = ReflectionResult("Clarity", 0.3, [], ["Low clarity"])
|
|
mistakes = ReflectionResult("Mistakes", 0.5, [], [])
|
|
context_ready = ReflectionResult("Context", 0.3, [], [])
|
|
|
|
mock_reflect.return_value = ConfidenceScore(
|
|
requirement_clarity=clarity,
|
|
mistake_check=mistakes,
|
|
context_ready=context_ready,
|
|
confidence=0.3,
|
|
should_proceed=False,
|
|
blockers=["Low confidence"],
|
|
recommendations=["Clarify task"],
|
|
)
|
|
|
|
with pytest.raises(RuntimeError, match="blocked"):
|
|
safe_execute(
|
|
task="vague task",
|
|
operation=lambda: "x",
|
|
)
|
|
|
|
|
|
class TestIntegration:
|
|
"""Integration tests for execution module"""
|
|
|
|
def test_full_workflow(self):
|
|
"""Test full intelligent execution workflow"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
# Create realistic project structure
|
|
(Path(tmpdir) / "PROJECT_INDEX.md").write_text(
|
|
"# Project Index\n## Structure"
|
|
)
|
|
|
|
context = {
|
|
"project_index": "loaded",
|
|
"current_branch": "feature/test",
|
|
"git_status": "clean",
|
|
}
|
|
|
|
executed = []
|
|
|
|
def op1():
|
|
executed.append("op1")
|
|
return "op1_result"
|
|
|
|
def op2():
|
|
executed.append("op2")
|
|
return "op2_result"
|
|
|
|
result = intelligent_execute(
|
|
task="Add two new functions to utils.py module file",
|
|
operations=[op1, op2],
|
|
context=context,
|
|
repo_path=Path(tmpdir),
|
|
)
|
|
|
|
# If not blocked, operations should have executed
|
|
if result["status"] != "blocked":
|
|
assert len(executed) == 2
|
|
|
|
def test_should_parallelize_helper(self):
|
|
"""Test should_parallelize helper function"""
|
|
assert should_parallelize([1]) is False
|
|
assert should_parallelize([1, 2]) is False
|
|
assert should_parallelize([1, 2, 3]) is True
|
|
assert should_parallelize([1, 2, 3, 4, 5]) is True
|