# #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