feat: 服务端集成自动打包流程
This commit is contained in:
+24
-109
@@ -1,118 +1,33 @@
|
||||
"""打包队列测试"""
|
||||
"""打包队列日志时序测试"""
|
||||
import asyncio
|
||||
|
||||
import pytest
|
||||
|
||||
from backend.services.build_queue import BuildQueue
|
||||
from backend.services.log_streamer import log_streamer
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def queue():
|
||||
return BuildQueue(max_concurrent=2)
|
||||
@pytest.mark.asyncio
|
||||
async def test_submit_creates_log_queue_before_worker_runs():
|
||||
"""前端订阅任务时,应能拿到入队日志和后续执行日志。"""
|
||||
task_id = "queue-log-test"
|
||||
log_streamer.cleanup(task_id)
|
||||
log_streamer._log_lines.pop(task_id, None)
|
||||
|
||||
queue = BuildQueue(max_concurrent=1)
|
||||
|
||||
def test_initial_state(queue):
|
||||
"""初始状态"""
|
||||
assert queue.queue_size == 0
|
||||
assert queue.running_count == 0
|
||||
async def build(task_id: str):
|
||||
await log_streamer.emit(task_id, "构建函数已执行")
|
||||
|
||||
try:
|
||||
await queue.submit(task_id, build)
|
||||
await asyncio.wait_for(queue._queue.join(), timeout=3)
|
||||
|
||||
def test_submit_starts_workers(queue):
|
||||
"""提交任务后自动启动 worker"""
|
||||
|
||||
async def dummy_build(task_id):
|
||||
pass
|
||||
|
||||
async def run():
|
||||
await queue.submit("t1", dummy_build)
|
||||
# 等待任务完成
|
||||
await asyncio.sleep(0.1)
|
||||
assert queue._started
|
||||
assert len(queue._workers) == 2
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(run())
|
||||
|
||||
|
||||
def test_task_executes(queue):
|
||||
"""任务被执行"""
|
||||
executed = []
|
||||
|
||||
async def mock_build(task_id):
|
||||
executed.append(task_id)
|
||||
|
||||
async def run():
|
||||
await queue.submit("t1", mock_build)
|
||||
await asyncio.sleep(0.2)
|
||||
return executed
|
||||
|
||||
result = asyncio.get_event_loop().run_until_complete(run())
|
||||
assert "t1" in result
|
||||
|
||||
|
||||
def test_concurrent_limit(queue):
|
||||
"""并发数不超过限制"""
|
||||
running = []
|
||||
max_concurrent = 0
|
||||
|
||||
async def slow_build(task_id):
|
||||
nonlocal max_concurrent
|
||||
running.append(task_id)
|
||||
max_concurrent = max(max_concurrent, len(running))
|
||||
await asyncio.sleep(0.3)
|
||||
running.remove(task_id)
|
||||
|
||||
async def run():
|
||||
tasks = []
|
||||
for i in range(5):
|
||||
tasks.append(queue.submit(f"t{i}", slow_build))
|
||||
await asyncio.gather(*tasks)
|
||||
await asyncio.sleep(1) # 等所有任务完成
|
||||
return max_concurrent
|
||||
|
||||
result = asyncio.get_event_loop().run_until_complete(run())
|
||||
assert result <= 2 # max_concurrent = 2
|
||||
|
||||
|
||||
def test_cancel_running_task(queue):
|
||||
"""取消运行中的任务"""
|
||||
cancelled = False
|
||||
|
||||
async def long_build(task_id):
|
||||
nonlocal cancelled
|
||||
try:
|
||||
await asyncio.sleep(10)
|
||||
except asyncio.CancelledError:
|
||||
cancelled = True
|
||||
raise
|
||||
|
||||
async def run():
|
||||
await queue.submit("t1", long_build)
|
||||
await asyncio.sleep(0.1) # 等任务开始
|
||||
queue.cancel("t1")
|
||||
await asyncio.sleep(0.2) # 等取消生效
|
||||
return cancelled
|
||||
|
||||
result = asyncio.get_event_loop().run_until_complete(run())
|
||||
assert result is True
|
||||
|
||||
|
||||
def test_cancel_nonexistent_task(queue):
|
||||
"""取消不存在的任务(不应报错)"""
|
||||
queue.cancel("nonexistent")
|
||||
|
||||
|
||||
def test_multiple_tasks(queue):
|
||||
"""多个任务顺序执行"""
|
||||
completed = []
|
||||
|
||||
async def mock_build(task_id):
|
||||
await asyncio.sleep(0.05)
|
||||
completed.append(task_id)
|
||||
|
||||
async def run():
|
||||
for i in range(4):
|
||||
await queue.submit(f"t{i}", mock_build)
|
||||
await asyncio.sleep(1)
|
||||
return completed
|
||||
|
||||
result = asyncio.get_event_loop().run_until_complete(run())
|
||||
assert len(result) == 4
|
||||
assert set(result) == {"t0", "t1", "t2", "t3"}
|
||||
messages = [entry["message"] for entry in log_streamer._log_lines[task_id]]
|
||||
assert messages == ["任务已加入队列,等待执行...", "构建函数已执行"]
|
||||
finally:
|
||||
for worker in queue._workers:
|
||||
worker.cancel()
|
||||
await asyncio.gather(*queue._workers, return_exceptions=True)
|
||||
log_streamer.cleanup(task_id)
|
||||
log_streamer._log_lines.pop(task_id, None)
|
||||
|
||||
Reference in New Issue
Block a user