Files
ss-tools/backend/tests/integration/test_translate_clickhouse.py
busya 50d6b9226e test(translate): add tests for ConnectionService, DbExecutor, orchestrator direct DB dispatch
- 9 new enhancement test files: test_connection_service.py,
  test_db_executor.py, test_orchestrator_direct_db.py, test_batch_insert.py,
  test_lang_stats.py, test_response_field_coverage.py, test_retry.py,
  test_run_service.py, test_sql_insert_service.py
- 5 new integration tests: test_superset_sqllab_e2e.py,
  test_translate_clickhouse.py, test_translate_corrections.py,
  test_translate_schedules.py, test_translate_status_fk.py
- Updated existing tests for insert_method/connection_id fields
2026-06-11 19:12:45 +03:00

182 lines
6.6 KiB
Python

# #region TestTranslateClickHouseIntegration [C:3] [TYPE Module] [SEMANTICS test,translate,clickhouse,integration]
# @BRIEF Integration tests for ClickHouse insert path using testcontainers.
# @RELATION BINDS_TO -> [_batch_insert_module]
# @RELATION BINDS_TO -> [SQLGenerator]
#
# @TEST_CONTRACT ClickHouseInsert ->
# SQL generation: clickhouse dialect -> valid INSERT SQL with backtick quoting
# Rows with timestamps: timestamp values encode to YYYY-MM-DD format
# Null handling: None values encode to NULL
# UPSERT: clickhouse supports INSERT with key_cols (uses INSERT ... VALUES)
#
# @REQUIRES Docker daemon running (testcontainers starts clickhouse server)
import pytest
import uuid
from testcontainers.clickhouse import ClickHouseContainer
from src.plugins.translate.sql_generator import SQLGenerator, _encode_sql_value
# #region clickhouse_container [C:2] [TYPE Fixture]
@pytest.fixture(scope="module")
def clickhouse_container():
"""Start a ClickHouse server for the test module."""
with ClickHouseContainer("clickhouse/clickhouse-server:24.3") as ch:
yield ch
# #endregion clickhouse_container
# #region clickhouse_client [C:2] [TYPE Fixture]
@pytest.fixture(scope="module")
def clickhouse_client(clickhouse_container):
"""clickhouse-connect client connected to the ClickHouse container."""
import clickhouse_connect
client = clickhouse_connect.get_client(
host=clickhouse_container.get_container_host_ip(),
port=int(clickhouse_container.get_exposed_port(8123)),
username="test",
password="test",
)
yield client
client.close()
# #endregion clickhouse_client
# #region TestClickHouseSQLGeneration [C:3] [TYPE Class]
class TestClickHouseSQLGeneration:
"""Verify SQL generation produces valid ClickHouse SQL."""
def test_generate_insert(self):
sql, count = SQLGenerator.generate(
dialect="clickhouse",
target_schema="",
target_table="test_table",
columns=["id", "name", "value"],
rows=[
{"id": 1, "name": "Alice", "value": "Hello"},
{"id": 2, "name": "Bob", "value": "World"},
],
key_columns=["id"],
upsert_strategy="INSERT",
)
assert sql is not None
assert "INSERT INTO" in sql
assert "test_table" in sql
assert "Alice" in sql
assert "Bob" in sql
assert count == 2
def test_generate_with_backtick_quoting(self):
sql, _ = SQLGenerator.generate(
dialect="clickhouse",
target_schema="",
target_table="test_table",
columns=["id", "translated-text"],
rows=[{"id": 1, "translated-text": "hello"}],
key_columns=["id"],
upsert_strategy="INSERT",
)
assert "`translated-text`" in sql
def test_encode_timestamp(self):
result = _encode_sql_value("1726358400000.0", dialect="clickhouse")
assert "2024" in result # should produce a date string
def test_encode_string(self):
result = _encode_sql_value("Hello World", dialect="clickhouse")
assert result == "'Hello World'"
def test_encode_none(self):
result = _encode_sql_value(None, dialect="clickhouse")
assert result == "NULL"
def test_encode_int(self):
result = _encode_sql_value(42, dialect="clickhouse")
assert result == "42"
def test_encode_bool(self):
result = _encode_sql_value(True, dialect="clickhouse")
assert result == "TRUE"
# #endregion TestClickHouseSQLGeneration
# #region TestClickHouseRealExecution [C:3] [TYPE Class]
class TestClickHouseRealExecution:
"""Execute generated SQL against a real ClickHouse container."""
@pytest.fixture(autouse=True)
def setup_table(self, clickhouse_client):
"""Create test table before each test."""
clickhouse_client.command("""
CREATE TABLE IF NOT EXISTS test_translations (
id UInt32,
source_text String,
translated_text String,
lang_code String,
is_original UInt8
) ENGINE = MergeTree()
ORDER BY id
""")
yield
clickhouse_client.command("DROP TABLE IF EXISTS test_translations")
def test_insert_and_select(self, clickhouse_client):
"""Insert rows and verify they can be selected."""
sql, count = SQLGenerator.generate(
dialect="clickhouse",
target_schema="",
target_table="test_translations",
columns=["id", "source_text", "translated_text", "lang_code", "is_original"],
rows=[
{"id": 1, "source_text": "Hello", "translated_text": "Привет", "lang_code": "ru", "is_original": 1},
{"id": 1, "source_text": "Hello", "translated_text": "Привет", "lang_code": "ru", "is_original": 0},
],
key_columns=["id"],
upsert_strategy="INSERT",
)
assert sql is not None
assert count == 2
clickhouse_client.command(sql)
result = clickhouse_client.query("SELECT count(*) FROM test_translations")
assert result.result_rows[0][0] == 2
def test_multiple_batches(self, clickhouse_client):
"""Insert in multiple chunks."""
rows = [{"id": i, "source_text": f"text_{i}", "translated_text": f"trans_{i}", "lang_code": "ru", "is_original": 1} for i in range(10)]
statements = SQLGenerator.generate_batch(
dialect="clickhouse",
target_schema="",
target_table="test_translations",
columns=["id", "source_text", "translated_text", "lang_code", "is_original"],
rows=rows,
key_columns=["id"],
upsert_strategy="INSERT",
max_rows_per_statement=3,
)
assert len(statements) == 4
for sql, chunk_count in statements:
clickhouse_client.command(sql)
result = clickhouse_client.query("SELECT count(*) FROM test_translations")
assert result.result_rows[0][0] == 10
def test_drop_and_reinsert(self, clickhouse_client):
"""Drop rows to verify idempotency."""
clickhouse_client.command("""
INSERT INTO test_translations (id, source_text, translated_text, lang_code, is_original)
VALUES (1, 'Hello', 'Привет', 'ru', 1)
""")
clickhouse_client.command("TRUNCATE TABLE test_translations")
result = clickhouse_client.query("SELECT count(*) FROM test_translations")
assert result.result_rows[0][0] == 0
# #endregion TestClickHouseRealExecution
# #endregion TestTranslateClickHouseIntegration