Files
erp-ass/backend/tests/test_executor.py
dazhuang acd73431ae feat: implement ERP AI Assistant Phase 1
Backend (FastAPI + SQLAlchemy + Claude API + RAG):
- Config management with Pydantic v2
- Database engine with connection pooling and SQL injection prevention
- AI engine with Claude API integration (support custom base URL)
- RAG engine with ChromaDB and sentence-transformers
- Requirement analysis service
- Config generation service
- Executor engine with SQL validation
- REST API endpoints: /analyze, /generate, /execute

Frontend (Vue 3 + Element Plus + Pinia):
- Complete 3-step workflow: analyze → generate → execute
- Step indicator with progress visualization
- Analysis result display with field table
- SQL preview with monospace font
- Execute confirmation dialog with safety warning
- Execution result display
- State management with Pinia
- API service integration

Security:
- SQL injection prevention with parameterized queries
- Dangerous SQL operation blocking
- Database password URL encoding
- Transaction auto-rollback
- Pydantic config validation

Features:
- Natural language requirement analysis
- Automated SQL configuration generation
- Safe execution with human review
- LAN access support
- Custom Claude API endpoint support

Documentation:
- README with quick start guide
- Quick start guide
- LAN access configuration
- Dependency fixes guide
- Claude API configuration
- Git operation guide
- Implementation report

Dependencies fixed:
- numpy<2.0.0 for chromadb compatibility
- sentence-transformers==2.7.0 for huggingface_hub compatibility

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 14:23:20 +00:00

141 lines
4.2 KiB
Python

"""Tests for Config Executor.
This module tests the ConfigExecutor class for SQL validation and execution.
"""
import pytest
from unittest.mock import MagicMock, patch
from app.core.executor import ConfigExecutor
def test_executor_init():
"""Test executor initialization."""
executor = ConfigExecutor()
assert executor.db_engine is not None
def test_validate_sql_safe():
"""Test validation of safe SQL statements."""
executor = ConfigExecutor()
# Test SELECT
is_valid, msg = executor.validate_sql("SELECT * FROM SYS_FORM")
assert is_valid is True
assert "验证通过" in msg
# Test INSERT
is_valid, msg = executor.validate_sql(
"INSERT INTO SYS_FORM (IKEY, FORM_NAME) VALUES (1, 'Test')"
)
assert is_valid is True
# Test UPDATE with safe WHERE clause
is_valid, msg = executor.validate_sql(
"UPDATE SYS_FORM SET FORM_NAME = 'Test' WHERE IKEY = 1"
)
assert is_valid is True
def test_validate_sql_dangerous():
"""Test validation catches dangerous SQL statements."""
executor = ConfigExecutor()
# Test DROP DATABASE
is_valid, msg = executor.validate_sql("DROP DATABASE test_db")
assert is_valid is False
assert "危险操作" in msg
# Test DROP TABLE
is_valid, msg = executor.validate_sql("DROP TABLE users")
assert is_valid is False
assert "危险操作" in msg
# Test TRUNCATE
is_valid, msg = executor.validate_sql("TRUNCATE TABLE important_data")
assert is_valid is False
assert "危险操作" in msg
# Test DELETE without WHERE
is_valid, msg = executor.validate_sql("DELETE FROM users")
assert is_valid is False
assert "危险操作" in msg
def test_execute_config_success():
"""Test successful execution of SQL list."""
with patch('app.core.executor.DatabaseEngine') as MockDBEngine:
mock_db_engine = MagicMock()
mock_db_engine.execute_transaction = MagicMock(return_value=True)
MockDBEngine.return_value = mock_db_engine
executor = ConfigExecutor()
sql_list = [
"INSERT INTO SYS_FORM (IKEY, FORM_NAME) VALUES (1, 'Test1')",
"INSERT INTO SYS_FORM (IKEY, FORM_NAME) VALUES (2, 'Test2')"
]
result = executor.execute_config(sql_list, session_id="test-session")
assert result["success"] is True
assert len(result["executed"]) == 2
assert result["failed"] is None
assert "成功执行" in result["message"]
def test_execute_config_validation_failure():
"""Test execution fails when SQL validation fails."""
executor = ConfigExecutor()
sql_list = [
"SELECT * FROM SYS_FORM",
"DROP DATABASE test" # Dangerous SQL
]
result = executor.execute_config(sql_list, session_id="test-session")
assert result["success"] is False
assert result["failed"] is not None
assert "验证失败" in result["message"]
assert len(result["executed"]) == 0
def test_execute_config_execution_failure():
"""Test execution handles database errors."""
with patch('app.core.executor.DatabaseEngine') as MockDBEngine:
mock_db_engine = MagicMock()
mock_db_engine.execute_transaction = MagicMock(
side_effect=Exception("Database connection error")
)
MockDBEngine.return_value = mock_db_engine
executor = ConfigExecutor()
sql_list = ["SELECT * FROM SYS_FORM"]
result = executor.execute_config(sql_list, session_id="test-session")
assert result["success"] is False
assert result["failed"] is not None
assert "执行失败" in result["message"]
def test_rollback_placeholder():
"""Test rollback functionality placeholder."""
executor = ConfigExecutor()
result = executor.rollback(session_id="test-session")
assert result["success"] is False
assert "待实现" in result["message"]
def test_dangerous_keywords_exist():
"""Test that dangerous keywords list is properly defined."""
executor = ConfigExecutor()
assert hasattr(executor, 'DANGEROUS_KEYWORDS')
assert len(executor.DANGEROUS_KEYWORDS) > 0
assert "DROP DATABASE" in executor.DANGEROUS_KEYWORDS
assert "DROP TABLE" in executor.DANGEROUS_KEYWORDS
assert "TRUNCATE TABLE" in executor.DANGEROUS_KEYWORDS