style: auto-format with black + isort + prettier
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m42s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m44s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m42s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 1m26s
CI/CD Pipeline / Validate - Code Quality (push) Failing after 3m13s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m22s
CI/CD Pipeline / Frontend Lint (push) Successful in 4m29s
CI/CD Pipeline / Integration Tests (push) Successful in 2m16s
CI/CD Pipeline / Unit Tests (push) Failing after 5m46s
CI/CD Pipeline / Build Staging API Image (push) Successful in 11m28s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 3m18s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 30s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 2m13s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 5m58s
CI/CD Pipeline / Production Browser E2E (push) Failing after 1289h2m32s
CI/CD Pipeline / Build Production Worker Image (push) Failing after 1289h5m6s
CI/CD Pipeline / Build Production Web Image (push) Failing after 1289h5m7s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 1289h6m49s
CI/CD Pipeline / PR Build Web Image (push) Failing after 1289h6m50s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 1289h6m52s
CI/CD Pipeline / Deploy Production (push) Failing after 1289h35m22s
CI/CD Pipeline / Build Production API Image (push) Failing after 1289h37m37s
CI/CD Pipeline / PR Build API Image (push) Failing after 1289h39m20s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m42s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m44s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m42s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 1m26s
CI/CD Pipeline / Validate - Code Quality (push) Failing after 3m13s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m22s
CI/CD Pipeline / Frontend Lint (push) Successful in 4m29s
CI/CD Pipeline / Integration Tests (push) Successful in 2m16s
CI/CD Pipeline / Unit Tests (push) Failing after 5m46s
CI/CD Pipeline / Build Staging API Image (push) Successful in 11m28s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 3m18s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 30s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 2m13s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 5m58s
CI/CD Pipeline / Production Browser E2E (push) Failing after 1289h2m32s
CI/CD Pipeline / Build Production Worker Image (push) Failing after 1289h5m6s
CI/CD Pipeline / Build Production Web Image (push) Failing after 1289h5m7s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 1289h6m49s
CI/CD Pipeline / PR Build Web Image (push) Failing after 1289h6m50s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 1289h6m52s
CI/CD Pipeline / Deploy Production (push) Failing after 1289h35m22s
CI/CD Pipeline / Build Production API Image (push) Failing after 1289h37m37s
CI/CD Pipeline / PR Build API Image (push) Failing after 1289h39m20s
This commit is contained in:
@@ -1,20 +1,19 @@
|
||||
"""task_enqueue 单测 — 队列限流 + 安全入队逻辑."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from app.core.task_enqueue import (
|
||||
USER_PENDING_LIMIT,
|
||||
GLOBAL_PENDING_LIMIT,
|
||||
UserPendingLimitExceeded,
|
||||
USER_PENDING_LIMIT,
|
||||
GlobalQueueFull,
|
||||
UserPendingLimitExceeded,
|
||||
check_queue_limits,
|
||||
safe_enqueue_generation_task,
|
||||
)
|
||||
|
||||
|
||||
# ── Fixtures / Helpers ─────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -57,18 +56,14 @@ class TestCheckQueueLimits:
|
||||
|
||||
def test_global_at_limit_raises(self):
|
||||
"""达到全局上限即拒绝."""
|
||||
repo = MockRepository(
|
||||
global_count=GLOBAL_PENDING_LIMIT, user_count=1
|
||||
)
|
||||
repo = MockRepository(global_count=GLOBAL_PENDING_LIMIT, user_count=1)
|
||||
with pytest.raises(GlobalQueueFull) as exc_info:
|
||||
check_queue_limits("user-1", repo)
|
||||
assert exc_info.value.pending_count == GLOBAL_PENDING_LIMIT
|
||||
assert exc_info.value.limit == GLOBAL_PENDING_LIMIT
|
||||
|
||||
def test_global_over_limit_raises(self):
|
||||
repo = MockRepository(
|
||||
global_count=GLOBAL_PENDING_LIMIT + 1, user_count=1
|
||||
)
|
||||
repo = MockRepository(global_count=GLOBAL_PENDING_LIMIT + 1, user_count=1)
|
||||
with pytest.raises(GlobalQueueFull):
|
||||
check_queue_limits("user-1", repo)
|
||||
|
||||
@@ -124,14 +119,10 @@ class TestSafeEnqueueGenerationTask:
|
||||
repo = MockRepository(global_count=1, user_count=1)
|
||||
task = make_mock_task()
|
||||
|
||||
result = safe_enqueue_generation_task(
|
||||
task, repo, user_id="user-1"
|
||||
)
|
||||
result = safe_enqueue_generation_task(task, repo, user_id="user-1")
|
||||
|
||||
assert result is True
|
||||
mock_celery.send_task.assert_called_once_with(
|
||||
"worker.generate_video", args=[task.id]
|
||||
)
|
||||
mock_celery.send_task.assert_called_once_with("worker.generate_video", args=[task.id])
|
||||
task.mark_failed.assert_not_called()
|
||||
|
||||
@patch("app.core.task_enqueue.celery_app")
|
||||
@@ -146,9 +137,7 @@ class TestSafeEnqueueGenerationTask:
|
||||
@patch("app.core.task_enqueue.celery_app")
|
||||
def test_precheck_global_over_marks_failed(self, mock_celery):
|
||||
"""入队前全局超限:标记 failed,抛异常."""
|
||||
repo = MockRepository(
|
||||
global_count=GLOBAL_PENDING_LIMIT + 1, user_count=0
|
||||
)
|
||||
repo = MockRepository(global_count=GLOBAL_PENDING_LIMIT + 1, user_count=0)
|
||||
task = make_mock_task()
|
||||
|
||||
with pytest.raises(GlobalQueueFull):
|
||||
@@ -161,9 +150,7 @@ class TestSafeEnqueueGenerationTask:
|
||||
@patch("app.core.task_enqueue.celery_app")
|
||||
def test_precheck_user_over_marks_failed(self, mock_celery):
|
||||
"""入队前用户超限:标记 failed,抛异常."""
|
||||
repo = MockRepository(
|
||||
global_count=5, user_count=USER_PENDING_LIMIT + 1
|
||||
)
|
||||
repo = MockRepository(global_count=5, user_count=USER_PENDING_LIMIT + 1)
|
||||
task = make_mock_task()
|
||||
|
||||
with pytest.raises(UserPendingLimitExceeded):
|
||||
@@ -211,9 +198,7 @@ class TestSafeEnqueueGenerationTask:
|
||||
return GLOBAL_PENDING_LIMIT + 1 # 入队后再查,超限
|
||||
|
||||
repo = MockRepository(global_count=GLOBAL_PENDING_LIMIT, user_count=0)
|
||||
repo.count_pending_total = MagicMock(
|
||||
side_effect=count_pending_total_side_effect
|
||||
)
|
||||
repo.count_pending_total = MagicMock(side_effect=count_pending_total_side_effect)
|
||||
task = make_mock_task()
|
||||
|
||||
with pytest.raises(GlobalQueueFull):
|
||||
@@ -227,9 +212,7 @@ class TestSafeEnqueueGenerationTask:
|
||||
@patch("app.core.task_enqueue.celery_app")
|
||||
def test_postcheck_user_over_rollback(self, mock_celery):
|
||||
"""入队后用户超限:回滚标记 failed,抛异常."""
|
||||
repo = MockRepository(
|
||||
global_count=5, user_count=USER_PENDING_LIMIT
|
||||
)
|
||||
repo = MockRepository(global_count=5, user_count=USER_PENDING_LIMIT)
|
||||
# 入队前用 > 判断,等于上限通过;入队后模拟并发超限
|
||||
original_user_count = repo.count_pending_by_user
|
||||
|
||||
@@ -241,9 +224,7 @@ class TestSafeEnqueueGenerationTask:
|
||||
return USER_PENDING_LIMIT # 用 > 判断,等于时通过
|
||||
return USER_PENDING_LIMIT + 1 # 入队后,超限
|
||||
|
||||
repo.count_pending_by_user = MagicMock(
|
||||
side_effect=count_by_user_side_effect
|
||||
)
|
||||
repo.count_pending_by_user = MagicMock(side_effect=count_by_user_side_effect)
|
||||
task = make_mock_task()
|
||||
|
||||
with pytest.raises(UserPendingLimitExceeded):
|
||||
@@ -257,9 +238,7 @@ class TestSafeEnqueueGenerationTask:
|
||||
repo = MockRepository(global_count=1, user_count=1)
|
||||
task = make_mock_task()
|
||||
|
||||
result = safe_enqueue_generation_task(
|
||||
task, repo, user_id="user-1", log_task_status=True
|
||||
)
|
||||
result = safe_enqueue_generation_task(task, repo, user_id="user-1", log_task_status=True)
|
||||
assert result is True
|
||||
|
||||
@patch("app.core.task_enqueue.celery_app")
|
||||
|
||||
Reference in New Issue
Block a user