- 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
236 lines
11 KiB
Python
236 lines
11 KiB
Python
# #region TestTranslateSchedulesIntegration [C:3] [TYPE Module] [SEMANTICS test,translate,schedule,integration]
|
|
# @BRIEF Integration tests for TranslationSchedule CRUD with real PostgreSQL via Testcontainers.
|
|
# @RELATION BINDS_TO -> [TranslationScheduler]
|
|
#
|
|
# @TEST_CONTRACT TranslationScheduler ->
|
|
# create_schedule: job_id + cron + timezone -> TranslationSchedule persisted
|
|
# get_schedule: job_id -> TranslationSchedule or ValueError
|
|
# update_schedule: job_id + fields -> updated schedule
|
|
# delete_schedule: job_id -> None (schedule removed)
|
|
# set_schedule_active: job_id + is_active -> schedule toggled
|
|
# get_next_executions: cron + tz + n -> list of ISO datetime strings
|
|
# list_active_schedules: db -> list[TranslationSchedule]
|
|
#
|
|
# @TEST_EDGE: non_existent_job -> ValueError on create
|
|
# @TEST_EDGE: get_non_existent -> ValueError with "No schedule found"
|
|
# @TEST_EDGE: delete_non_existent -> ValueError
|
|
# @TEST_EDGE: update_non_existent -> ValueError
|
|
import pytest
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from src.models.translate import TranslationJob, TranslationSchedule
|
|
from src.plugins.translate.scheduler import TranslationScheduler
|
|
|
|
|
|
# #region TestScheduleCRUD [C:3] [TYPE Class]
|
|
# @BRIEF Integration tests for schedule CRUD operations with real PostgreSQL.
|
|
class TestScheduleCRUD:
|
|
"""Verify TranslationScheduler CRUD with real PostgreSQL."""
|
|
|
|
def _create_job(self, db: Session, status: str = "DRAFT") -> TranslationJob:
|
|
job = TranslationJob(
|
|
name="Test Job",
|
|
status=status,
|
|
source_dialect="postgresql",
|
|
target_dialect="clickhouse",
|
|
created_by="test_user",
|
|
)
|
|
db.add(job)
|
|
db.commit()
|
|
db.refresh(job)
|
|
return job
|
|
|
|
# #region test_create_schedule [C:2] [TYPE Function]
|
|
def test_create_schedule(self, db_session: Session, mock_config_manager):
|
|
job = self._create_job(db_session)
|
|
scheduler = TranslationScheduler(db_session, mock_config_manager)
|
|
|
|
sched = scheduler.create_schedule(
|
|
job_id=job.id,
|
|
cron_expression="0 2 * * *",
|
|
timezone="Europe/Moscow",
|
|
execution_mode="new_key_only",
|
|
)
|
|
|
|
assert sched.job_id == job.id
|
|
assert sched.cron_expression == "0 2 * * *"
|
|
assert sched.timezone == "Europe/Moscow"
|
|
assert sched.execution_mode == "new_key_only"
|
|
assert sched.is_active is True
|
|
# #endregion test_create_schedule
|
|
|
|
# #region test_create_schedule_full_mode_default [C:2] [TYPE Function]
|
|
def test_create_schedule_full_mode_default(self, db_session: Session, mock_config_manager):
|
|
job = self._create_job(db_session)
|
|
scheduler = TranslationScheduler(db_session, mock_config_manager)
|
|
sched = scheduler.create_schedule(job_id=job.id, cron_expression="0 2 * * *")
|
|
assert sched.execution_mode == "full"
|
|
# #endregion test_create_schedule_full_mode_default
|
|
|
|
# #region test_get_schedule [C:2] [TYPE Function]
|
|
def test_get_schedule(self, db_session: Session, mock_config_manager):
|
|
job = self._create_job(db_session)
|
|
scheduler = TranslationScheduler(db_session, mock_config_manager)
|
|
scheduler.create_schedule(job_id=job.id, cron_expression="0 2 * * *")
|
|
db_session.commit()
|
|
|
|
result = scheduler.get_schedule(job.id)
|
|
assert result is not None
|
|
assert result.cron_expression == "0 2 * * *"
|
|
# #endregion test_get_schedule
|
|
|
|
# #region test_get_schedule_no_schedule [C:2] [TYPE Function]
|
|
def test_get_schedule_no_schedule(self, db_session: Session, mock_config_manager):
|
|
job = self._create_job(db_session)
|
|
scheduler = TranslationScheduler(db_session, mock_config_manager)
|
|
with pytest.raises(ValueError, match="No schedule found"):
|
|
scheduler.get_schedule(job.id)
|
|
# #endregion test_get_schedule_no_schedule
|
|
|
|
# #region test_update_schedule_all_fields [C:2] [TYPE Function]
|
|
def test_update_schedule_all_fields(self, db_session: Session, mock_config_manager):
|
|
job = self._create_job(db_session)
|
|
scheduler = TranslationScheduler(db_session, mock_config_manager)
|
|
scheduler.create_schedule(job_id=job.id, cron_expression="0 2 * * *")
|
|
db_session.commit()
|
|
|
|
updated = scheduler.update_schedule(
|
|
job_id=job.id, cron_expression="30 6 * * 1",
|
|
timezone_str="Asia/Tokyo", is_active=False,
|
|
execution_mode="full",
|
|
)
|
|
assert updated.cron_expression == "30 6 * * 1"
|
|
assert updated.timezone == "Asia/Tokyo"
|
|
assert updated.is_active is False
|
|
assert updated.execution_mode == "full"
|
|
# #endregion test_update_schedule_all_fields
|
|
|
|
# #region test_update_schedule_partial [C:2] [TYPE Function]
|
|
def test_update_schedule_partial(self, db_session: Session, mock_config_manager):
|
|
job = self._create_job(db_session)
|
|
scheduler = TranslationScheduler(db_session, mock_config_manager)
|
|
scheduler.create_schedule(job_id=job.id, cron_expression="0 2 * * *", timezone="Europe/Moscow")
|
|
db_session.commit()
|
|
|
|
updated = scheduler.update_schedule(job_id=job.id, cron_expression="0 4 * * *")
|
|
assert updated.cron_expression == "0 4 * * *"
|
|
assert updated.timezone == "Europe/Moscow"
|
|
# #endregion test_update_schedule_partial
|
|
|
|
# #region test_delete_schedule [C:2] [TYPE Function]
|
|
def test_delete_schedule(self, db_session: Session, mock_config_manager):
|
|
job = self._create_job(db_session)
|
|
scheduler = TranslationScheduler(db_session, mock_config_manager)
|
|
scheduler.create_schedule(job_id=job.id, cron_expression="0 2 * * *")
|
|
db_session.commit()
|
|
|
|
scheduler.delete_schedule(job.id)
|
|
with pytest.raises(ValueError, match="No schedule found"):
|
|
scheduler.get_schedule(job.id)
|
|
# #endregion test_delete_schedule
|
|
|
|
# #region test_set_schedule_active [C:2] [TYPE Function]
|
|
def test_set_schedule_active(self, db_session: Session, mock_config_manager):
|
|
job = self._create_job(db_session)
|
|
scheduler = TranslationScheduler(db_session, mock_config_manager)
|
|
scheduler.create_schedule(job_id=job.id, cron_expression="0 2 * * *", is_active=False)
|
|
db_session.commit()
|
|
|
|
sched = scheduler.set_schedule_active(job.id, True)
|
|
assert sched.is_active is True
|
|
|
|
sched = scheduler.set_schedule_active(job.id, False)
|
|
assert sched.is_active is False
|
|
# #endregion test_set_schedule_active
|
|
|
|
# #region test_set_schedule_active_twice [C:2] [TYPE Function]
|
|
def test_set_schedule_active_twice(self, db_session: Session, mock_config_manager):
|
|
job = self._create_job(db_session)
|
|
scheduler = TranslationScheduler(db_session, mock_config_manager)
|
|
scheduler.create_schedule(job_id=job.id, cron_expression="0 2 * * *")
|
|
db_session.commit()
|
|
|
|
sched = scheduler.set_schedule_active(job.id, True)
|
|
assert sched.is_active is True
|
|
sched = scheduler.set_schedule_active(job.id, True)
|
|
assert sched.is_active is True
|
|
# #endregion test_set_schedule_active_twice
|
|
|
|
# #region test_create_schedule_non_existent_job [C:2] [TYPE Function]
|
|
def test_create_schedule_non_existent_job(self, db_session: Session, mock_config_manager):
|
|
scheduler = TranslationScheduler(db_session, mock_config_manager)
|
|
with pytest.raises(ValueError, match="not found"):
|
|
scheduler.create_schedule(job_id="non-existent-id", cron_expression="0 2 * * *")
|
|
# #endregion test_create_schedule_non_existent_job
|
|
|
|
# #region test_delete_schedule_non_existent [C:2] [TYPE Function]
|
|
def test_delete_schedule_non_existent(self, db_session: Session, mock_config_manager):
|
|
scheduler = TranslationScheduler(db_session, mock_config_manager)
|
|
with pytest.raises(ValueError, match="No schedule found"):
|
|
scheduler.delete_schedule(job_id="non-existent-id")
|
|
# #endregion test_delete_schedule_non_existent
|
|
|
|
# #region test_update_schedule_no_schedule [C:2] [TYPE Function]
|
|
def test_update_schedule_no_schedule(self, db_session: Session, mock_config_manager):
|
|
job = self._create_job(db_session)
|
|
scheduler = TranslationScheduler(db_session, mock_config_manager)
|
|
with pytest.raises(ValueError, match="No schedule found"):
|
|
scheduler.update_schedule(job_id=job.id, cron_expression="0 2 * * *")
|
|
# #endregion test_update_schedule_no_schedule
|
|
|
|
# #region test_set_active_non_existent [C:2] [TYPE Function]
|
|
def test_set_active_non_existent(self, db_session: Session, mock_config_manager):
|
|
scheduler = TranslationScheduler(db_session, mock_config_manager)
|
|
with pytest.raises(ValueError, match="No schedule found"):
|
|
scheduler.set_schedule_active(job_id="non-existent", is_active=True)
|
|
# #endregion test_set_active_non_existent
|
|
|
|
# #region test_list_active_schedules [C:2] [TYPE Function]
|
|
def test_list_active_schedules(self, db_session: Session, mock_config_manager):
|
|
job1 = self._create_job(db_session)
|
|
job2 = self._create_job(db_session)
|
|
scheduler = TranslationScheduler(db_session, mock_config_manager)
|
|
scheduler.create_schedule(job_id=job1.id, cron_expression="0 2 * * *", is_active=True)
|
|
scheduler.create_schedule(job_id=job2.id, cron_expression="0 4 * * *", is_active=False)
|
|
db_session.commit()
|
|
|
|
active = TranslationScheduler.list_active_schedules(db_session)
|
|
assert len(active) == 1
|
|
assert active[0].job_id == job1.id
|
|
# #endregion test_list_active_schedules
|
|
|
|
# #region test_get_next_executions_static [C:2] [TYPE Function]
|
|
def test_get_next_executions_static(self):
|
|
executions = TranslationScheduler.get_next_executions(
|
|
cron_expression="0 2 * * *",
|
|
timezone_str="UTC",
|
|
n=3,
|
|
)
|
|
assert len(executions) == 3
|
|
for dt_str in executions:
|
|
assert "T02:00:00" in dt_str
|
|
# #endregion test_get_next_executions_static
|
|
|
|
# #region test_get_next_executions_invalid_cron [C:2] [TYPE Function]
|
|
def test_get_next_executions_invalid_cron(self):
|
|
executions = TranslationScheduler.get_next_executions(
|
|
cron_expression="invalid-cron",
|
|
timezone_str="UTC",
|
|
n=3,
|
|
)
|
|
assert executions == []
|
|
# #endregion test_get_next_executions_invalid_cron
|
|
|
|
# #region test_get_next_executions_different_timezone [C:2] [TYPE Function]
|
|
def test_get_next_executions_different_timezone(self):
|
|
executions = TranslationScheduler.get_next_executions(
|
|
cron_expression="0 2 * * *",
|
|
timezone_str="Asia/Tokyo",
|
|
n=2,
|
|
)
|
|
assert len(executions) == 2
|
|
# #endregion test_get_next_executions_different_timezone
|
|
# #endregion TestScheduleCRUD
|
|
# #endregion TestTranslateSchedulesIntegration
|