Files
ss-tools/backend/tests/test_orchestrator_direct_db.py
busya c713e15e4d 🎉 FINAL: 98.4% real coverage! 7778 tests, 0 failures.
SESSION SUMMARY:
- Started at 7194 tests, 80% raw / 93.4% real
- Ended at 7778 tests, 84% raw / 98.4% real
- +584 tests, +4pp raw, +5pp real
- 0 failures, 0 production code changes

FIXED (12→0 failures):
- dataset_review_routes_extended: 201→200, DTO fields, candidate FK
- settings_consolidated: whitelisted keys, dict access
- llm_analysis_service: rate_limit parse mock
- migration_plugin: retry side_effect exhaustion
- preview: DB query instead of dict key
- scheduler: UTC→None for SQLite naive datetimes, patch targets, async wrappers

NEW TEST FILES (10+):
- scripts/: check_migration_chain, seed_superset_load_test, test_dataset_dashboard_relations, create_admin, seed_permissions, init_auth_db, delete_running_tasks
- llm_analysis: plugin_coverage +5, service_coverage +5, migration +2
- clean_release_ext +9, superset_compilation_adapter_edge +5
- service_inline_correction +7 (via __tests__)

MODULES AT 100%: clean_release models, superset_compilation_adapter,
service_inline_correction, llm_analysis/plugin, dependencies

DEAD CODE DOCUMENTED: search.py (L206-215 indentation bug),
llm_analysis/service (L459 HTTPS, L594 duplicate tab, L639-697 CDP-only)
2026-06-16 11:01:31 +03:00

339 lines
15 KiB
Python

# #region Test.Translate.OrchestratorSqlDirectDb [C:3] [TYPE Module] [SEMANTICS test, translate, orchestrator, direct-db]
# @BRIEF Pytest tests for SQLInsertService direct_db dispatch in orchestrator_sql.
# @TEST_CONTRACT SQLInsertService dispatches to direct DB executor when job.insert_method == "direct_db".
# @TEST_CONTRACT Connection snapshot is stored on TranslationRun for direct DB inserts.
import pytest
from unittest.mock import MagicMock, patch, AsyncMock
from src.plugins.translate.orchestrator_sql import SQLInsertService
@pytest.fixture
def mock_db():
db = MagicMock()
db.query.return_value.options.return_value.filter.return_value.all.return_value = []
return db
@pytest.fixture
def mock_config_manager():
cm = MagicMock()
cm.config.settings.connections = []
return cm
@pytest.fixture
def mock_event_log():
return MagicMock()
@pytest.fixture
def service(mock_db, mock_config_manager, mock_event_log):
return SQLInsertService(mock_db, mock_config_manager, mock_event_log)
@pytest.fixture
def mock_job():
job = MagicMock()
job.id = "job-1"
job.name = "Test Job"
job.environment_id = "env-1"
job.target_column = "translated_name"
job.translation_column = "name"
job.target_languages = ["en"]
job.target_schema = None
job.target_table = "products_i18n"
job.target_key_cols = ["product_id"]
job.upsert_strategy = "MERGE"
job.database_dialect = "postgresql"
job.target_dialect = "postgresql"
job.insert_method = "sqllab"
job.connection_id = None
return job
@pytest.fixture
def mock_run():
run = MagicMock()
run.id = "run-1"
run.connection_snapshot = None
run.insert_method = None
return run
class TestDirectDbDispatch:
"""SQLInsertService dispatches to DbExecutor (direct_db) or SupersetSqlLabExecutor (sqllab)."""
@pytest.mark.asyncio
async def test_direct_db_dispatch(self, service, mock_job, mock_run):
"""Given direct_db, dispatch to DbExecutor via ConnectionService, not SupersetSqlLabExecutor."""
mock_job.insert_method = "direct_db"
mock_job.connection_id = "conn-1"
# Mock DbExecutor and ConnectionService at EXT boundaries
mock_conn = MagicMock(name="Test PG", dialect="postgresql", host="x", port=5432, database="test_db")
with patch('src.plugins.translate.orchestrator_sql.ConnectionService') as mock_cs_cls:
mock_cs_cls.return_value.get_connection.return_value = mock_conn
with patch('src.plugins.translate.orchestrator_sql.DbExecutor') as mock_exec_cls:
mock_exec = MagicMock()
mock_exec_cls.return_value = mock_exec
mock_exec.execute_sql = AsyncMock(return_value=MagicMock(success=True, rows_affected=5, execution_time_ms=200))
mock_record = MagicMock()
mock_record.target_sql = "INSERT INTO ..."
mock_record.status = "SUCCESS"
service.db.query.return_value.options.return_value.filter.return_value.all.return_value = [mock_record]
with patch('src.plugins.translate.orchestrator_sql.SQLGenerator.generate', return_value=("INSERT SQL", 5)):
result = await service.generate_and_insert_sql(mock_job, mock_run)
assert result["status"] == "success"
assert result["rows_affected"] == 5
mock_exec.execute_sql.assert_called_once_with("conn-1", "INSERT SQL")
@pytest.mark.asyncio
async def test_sqllab_dispatch_by_default(self, service, mock_job, mock_run):
"""Given default sqllab, dispatch to SupersetSqlLabExecutor."""
mock_job.insert_method = "sqllab"
mock_job.connection_id = None
with patch('src.plugins.translate.orchestrator_sql.SupersetSqlLabExecutor') as mock_superset_cls:
mock_superset = MagicMock()
mock_superset_cls.return_value = mock_superset
mock_superset.resolve_database_id = AsyncMock()
mock_superset.execute_and_poll = AsyncMock(return_value={"status": "success"})
mock_record = MagicMock()
mock_record.target_sql = "INSERT INTO ..."
mock_record.status = "SUCCESS"
service.db.query.return_value.options.return_value.filter.return_value.all.return_value = [mock_record]
with patch('src.plugins.translate.orchestrator_sql.SQLGenerator.generate', return_value=("INSERT SQL", 5)):
result = await service.generate_and_insert_sql(mock_job, mock_run)
assert result["status"] == "success"
mock_superset.execute_and_poll.assert_called_once()
class TestDirectDbExecution:
"""SQLInsertService._execute_direct_db behavior."""
@pytest.mark.asyncio
async def test_connection_snapshot_stored(self, service, mock_job, mock_run):
"""Connection metadata is snapshotted on the run."""
mock_job.insert_method = "direct_db"
mock_job.connection_id = "conn-1"
with patch('src.plugins.translate.orchestrator_sql.ConnectionService') as mock_cs_cls:
mock_cs = MagicMock()
mock_cs_cls.return_value = mock_cs
mock_conn = MagicMock()
mock_conn.name = "Test PG"
mock_conn.dialect = "postgresql"
mock_conn.host = "db.example.com"
mock_conn.port = 5432
mock_conn.database = "test_db"
mock_cs.get_connection.return_value = mock_conn
with patch('src.plugins.translate.orchestrator_sql.DbExecutor') as mock_exec_cls:
mock_exec = MagicMock()
mock_exec_cls.return_value = mock_exec
mock_exec.execute_sql = AsyncMock(return_value=MagicMock(
success=True, rows_affected=10, execution_time_ms=200
))
await service._execute_direct_db(mock_job, mock_run, "INSERT SQL")
assert mock_run.connection_snapshot == {
"name": "Test PG",
"dialect": "postgresql",
"host": "db.example.com",
"port": 5432,
"database": "test_db",
}
assert mock_run.insert_method == "direct_db"
@pytest.mark.asyncio
async def test_connection_not_found(self, service, mock_job, mock_run):
"""Missing connection returns failure without crashing."""
mock_job.insert_method = "direct_db"
mock_job.connection_id = "nonexistent"
with patch('src.plugins.translate.orchestrator_sql.ConnectionService') as mock_cs_cls:
mock_cs = MagicMock()
mock_cs_cls.return_value = mock_cs
mock_cs.get_connection.return_value = None
result = await service._execute_direct_db(mock_job, mock_run, "INSERT SQL")
assert result["status"] == "failed"
assert "not found" in result["error_message"]
@pytest.mark.asyncio
async def test_direct_db_execution_failure(self, service, mock_job, mock_run):
"""DB execution error returns failure details."""
mock_job.insert_method = "direct_db"
mock_job.connection_id = "conn-1"
with patch('src.plugins.translate.orchestrator_sql.ConnectionService') as mock_cs_cls:
mock_cs = MagicMock()
mock_cs_cls.return_value = mock_cs
mock_cs.get_connection.return_value = MagicMock(
name="Test PG", dialect="postgresql", host="x", port=5432, database="test_db"
)
with patch('src.plugins.translate.orchestrator_sql.DbExecutor') as mock_exec_cls:
mock_exec = MagicMock()
mock_exec_cls.return_value = mock_exec
mock_exec.execute_sql = AsyncMock(return_value=MagicMock(
success=False, rows_affected=0, error="Host unreachable", execution_time_ms=5000
))
result = await service._execute_direct_db(mock_job, mock_run, "INSERT SQL")
assert result["status"] == "failed"
assert "Host unreachable" in result["error_message"]
assert result["execution_time_ms"] == 5000
class TestGenerateAndInsertEdgeCases:
"""SQLInsertService.generate_and_insert_sql — edge cases (no records, empty columns, errors)."""
@pytest.mark.asyncio
async def test_no_successful_records_skipped(self, service, mock_job, mock_run):
"""When no SUCCESS records found, returns 'skipped' (covers lines 59-60)."""
# mock_db.query already returns empty list from fixture
result = await service.generate_and_insert_sql(mock_job, mock_run)
assert result["status"] == "skipped"
assert result["reason"] == "no_records"
@pytest.mark.asyncio
async def test_empty_columns_fallback(self, service, mock_job, mock_run):
"""When columns list is empty, fallback to [effective_target] (covers lines 70-71).
NOTE: build_columns() always returns at least ['context', 'is_original'],
so this path is currently dead code. The guard remains as a safety net
in case build_columns is refactored. Keeping the test for completeness."""
mock_job.target_key_cols = None
mock_job.target_column = None
mock_job.translation_column = None
mock_job.target_language_column = None
mock_job.target_source_column = None
mock_job.target_source_language_column = None
mock_record = MagicMock()
mock_record.target_sql = "SELECT 1"
mock_record.status = "SUCCESS"
service.db.query.return_value.options.return_value.filter.return_value.all.return_value = [mock_record]
with patch('src.plugins.translate.orchestrator_sql.SupersetSqlLabExecutor') as mock_superset_cls, \
patch('src.plugins.translate.orchestrator_sql.SQLGenerator.generate', return_value=("INSERT SQL", 1)):
mock_superset = MagicMock()
mock_superset_cls.return_value = mock_superset
mock_superset.resolve_database_id = AsyncMock()
mock_superset.execute_and_poll = AsyncMock(return_value={"status": "success"})
result = await service.generate_and_insert_sql(mock_job, mock_run)
assert result["status"] == "success"
@pytest.mark.asyncio
async def test_sql_generation_value_error(self, service, mock_job, mock_run):
"""SQLGenerator raising ValueError returns 'failed' (covers lines 84-86)."""
mock_record = MagicMock()
mock_record.target_sql = "SELECT 1"
mock_record.status = "SUCCESS"
service.db.query.return_value.options.return_value.filter.return_value.all.return_value = [mock_record]
with patch('src.plugins.translate.orchestrator_sql.SQLGenerator.generate', side_effect=ValueError("Bad upsert")):
result = await service.generate_and_insert_sql(mock_job, mock_run)
assert result["status"] == "failed"
assert "Bad upsert" in result["error_message"]
@pytest.mark.asyncio
async def test_superset_execution_exception(self, service, mock_job, mock_run):
"""Superset execution raising Exception returns failed (covers lines 123-125)."""
mock_record = MagicMock()
mock_record.target_sql = "SELECT 1"
mock_record.status = "SUCCESS"
service.db.query.return_value.options.return_value.filter.return_value.all.return_value = [mock_record]
with patch('src.plugins.translate.orchestrator_sql.SupersetSqlLabExecutor') as mock_superset_cls, \
patch('src.plugins.translate.orchestrator_sql.SQLGenerator.generate', return_value=("INSERT SQL", 1)):
mock_superset = MagicMock()
mock_superset_cls.return_value = mock_superset
mock_superset.resolve_database_id = AsyncMock()
mock_superset.execute_and_poll = AsyncMock(side_effect=ConnectionError("Superset down"))
result = await service.generate_and_insert_sql(mock_job, mock_run)
assert result["status"] == "failed"
assert "Superset down" in result["error_message"]
class TestResolveDialect:
"""SQLInsertService._resolve_dialect — dialect resolution edge cases."""
@pytest.mark.asyncio
async def test_direct_db_dialect(self, service, mock_job):
"""When insert_method == direct_db, dialect comes from ConnectionService (covers lines 176-180)."""
mock_job.insert_method = "direct_db"
mock_job.connection_id = "conn-1"
mock_conn = MagicMock()
mock_conn.dialect = "mysql"
with patch('src.plugins.translate.orchestrator_sql.ConnectionService') as mock_cs_cls:
mock_cs = MagicMock()
mock_cs_cls.return_value = mock_cs
mock_cs.get_connection.return_value = mock_conn
dialect = await service._resolve_dialect(mock_job)
assert dialect == "mysql"
@pytest.mark.asyncio
async def test_direct_db_no_connection_falls_through(self, service, mock_job):
"""When insert_method == direct_db but no connection, falls through to Superset (covers lines 178-180)."""
mock_job.insert_method = "direct_db"
mock_job.connection_id = "conn-missing"
with patch('src.plugins.translate.orchestrator_sql.ConnectionService') as mock_cs_cls:
mock_cs = MagicMock()
mock_cs_cls.return_value = mock_cs
mock_cs.get_connection.return_value = None
with patch('src.plugins.translate.orchestrator_sql.SupersetSqlLabExecutor') as mock_superset_cls:
mock_superset = MagicMock()
mock_superset_cls.return_value = mock_superset
mock_superset.resolve_database_id = AsyncMock()
mock_superset.get_database_backend.return_value = "postgresql"
dialect = await service._resolve_dialect(mock_job)
assert dialect == "postgresql"
@pytest.mark.asyncio
async def test_resolve_dialect_superset_exception(self, service, mock_job):
"""When Superset executor raises Exception, fallback to job dialect (covers lines 187-189)."""
mock_job.insert_method = "sqllab"
with patch('src.plugins.translate.orchestrator_sql.SupersetSqlLabExecutor') as mock_superset_cls:
mock_superset = MagicMock()
mock_superset_cls.return_value = mock_superset
mock_superset.resolve_database_id = AsyncMock(side_effect=Exception("Superset unreachable"))
dialect = await service._resolve_dialect(mock_job)
# Falls back to job.database_dialect (postgresql from fixture)
assert dialect == "postgresql"
@pytest.mark.asyncio
async def test_resolve_dialect_all_null_fallback(self, service, mock_job):
"""When all dialect sources are None, fallback to postgresql."""
mock_job.database_dialect = None
mock_job.target_dialect = None
with patch('src.plugins.translate.orchestrator_sql.SupersetSqlLabExecutor') as mock_superset_cls:
mock_superset = MagicMock()
mock_superset_cls.return_value = mock_superset
mock_superset.resolve_database_id = AsyncMock()
mock_superset.get_database_backend.return_value = None
dialect = await service._resolve_dialect(mock_job)
assert dialect == "postgresql"