import pytest import asyncio import threading import sys sys.path.insert(0, '/Users/Chiguyong/Code/Fischer/geo/backend') from datetime import datetime, timezone # 模块级别事件循环,用于在测试运行时保持调度器活跃 _loop = None _loop_thread = None def start_scheduler_in_background(): """在后台线程中启动调度器的事件循环""" from app.workers.scheduler import query_scheduler global _loop, _loop_thread if query_scheduler.scheduler.running: return def run_loop(): global _loop _loop = asyncio.new_event_loop() asyncio.set_event_loop(_loop) _loop.run_until_complete(start_scheduler_async()) async def start_scheduler_async(): from app.workers.scheduler import query_scheduler query_scheduler.start() _loop_thread = threading.Thread(target=run_loop, daemon=True) _loop_thread.start() _loop_thread.join(timeout=2) # 等待启动 @pytest.fixture(scope="module", autouse=True) def scheduler_running(): """启动调度器""" start_scheduler_in_background() yield class TestScheduler: """定时调度器测试""" def test_scheduler_job_registered(self): """调度器应注册所需任务""" from app.workers.scheduler import query_scheduler # 获取所有注册的任务 jobs = query_scheduler.scheduler.get_jobs() job_ids = [job.id for job in jobs] # 应包含检查查询任务 assert "check_queries" in job_ids # 应包含检查pending任务 assert "check_pending_tasks" in job_ids def test_job_can_be_triggered_manually(self): """任务应支持手动触发""" from app.workers.scheduler import run_job_now, query_scheduler # 验证任务可以被获取 job = query_scheduler.scheduler.get_job("check_queries") assert job is not None assert callable(job.func) # 验证run_job_now返回True表示成功 result = run_job_now("check_queries") assert result is True def test_run_job_now_returns_false_for_unknown_job(self): """不存在的任务应返回False""" from app.workers.scheduler import run_job_now result = run_job_now("nonexistent_job") assert result is False def test_job_id_is_unique(self): """任务ID应唯一""" from app.workers.scheduler import query_scheduler jobs = query_scheduler.scheduler.get_jobs() job_ids = [job.id for job in jobs] assert len(job_ids) == len(set(job_ids)) def test_job_next_run_time_is_valid(self): """任务的下次运行时间应有效""" from app.workers.scheduler import query_scheduler jobs = query_scheduler.scheduler.get_jobs() now = datetime.now(timezone.utc) for job in jobs: assert job.next_run_time is not None # 应该是未来时间 job_time = job.next_run_time if job_time.tzinfo is None: job_time = job_time.replace(tzinfo=timezone.utc) assert job_time > now def test_job_stores_metadata(self): """任务应存储元数据""" from app.workers.scheduler import query_scheduler jobs = query_scheduler.scheduler.get_jobs() for job in jobs: # 任务应有ID和名称 assert hasattr(job, 'id') assert hasattr(job, 'name') assert job.id is not None assert job.name is not None def test_scheduler_has_two_jobs(self): """调度器应有两个注册的任务""" from app.workers.scheduler import query_scheduler jobs = query_scheduler.scheduler.get_jobs() assert len(jobs) == 2 def test_check_queries_job_config(self): """检查check_queries任务配置""" from app.workers.scheduler import query_scheduler job = query_scheduler.scheduler.get_job("check_queries") assert job is not None assert job.name == "检查并执行到期的查询任务" def test_check_pending_tasks_job_config(self): """检查check_pending_tasks任务配置""" from app.workers.scheduler import query_scheduler job = query_scheduler.scheduler.get_job("check_pending_tasks") assert job is not None assert job.name == "检查并执行遗留的pending查询任务" def test_scheduler_instance_is_singleton(self): """query_scheduler应是单例""" from app.workers.scheduler import query_scheduler, query_scheduler as qs2 assert query_scheduler is qs2