feat: 测试端点限流(每租户5次/15分钟)
- email/test 与 push/test 复用 LoginLimiter 滑动窗模式: (kind, tenant_slug) 键每租户 15 分钟 5 次真实出站,超限 429——guard 在端点最前(鉴权后), 被限流的租户连 400 预检也不触发;record 只落在通过全部预检真正出站 的那次(校验失败/未配置不消耗预算,两端口预算按 kind 互不挤占) - conftest autouse 复位限流器(跨测试隔离);新增三测: 第 6 次 429+ 不同租户独立+email/push 互不挤占、校验失败不耗预算 - 回归: 后端 630 passed(627+3) Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -225,6 +225,37 @@ def test_push_test_unknown_tenant_404(super_client, monkeypatch):
|
||||
assert r.status_code == 404
|
||||
|
||||
|
||||
def test_push_test_rate_limited_after_5(super_client, monkeypatch):
|
||||
"""限流(Phase 4 Task 5B): 每租户 15 分钟 5 次探测——前 5 次 200,
|
||||
第 6 次 429;email 与 push 预算互不挤占;不同租户独立。"""
|
||||
_create(super_client, slug="demo")
|
||||
_create(super_client, slug="other", profile="auto")
|
||||
assert _put_push_group(super_client, "demo", PUSH_GROUP).status_code == 200
|
||||
calls = _install_fake_client(monkeypatch, _ok)
|
||||
|
||||
for i in range(5):
|
||||
r = _post_test(super_client, "demo")
|
||||
assert r.status_code == 200, f"第 {i + 1} 次不应限流: {r.text}"
|
||||
r = _post_test(super_client, "demo")
|
||||
assert r.status_code == 429
|
||||
assert "频繁" in r.json()["detail"]
|
||||
assert len(_post_calls(calls)) == 5 # 第 6 次不再出站
|
||||
|
||||
# email 预算独立(键含 kind): 同租户 email/test 不受 push 拉满影响
|
||||
# (不配置 SMTP → 400 业务分支,证明 guard 放行)
|
||||
monkeypatch.setattr(settings, "SMTP_HOST", "")
|
||||
monkeypatch.setattr(settings, "SMTP_USER", "")
|
||||
r = super_client.post(f"/api/platform/tenants/demo/email/test",
|
||||
headers=_auth(super_client), json={"to": "a@b.com"})
|
||||
assert r.status_code == 400
|
||||
|
||||
# 不同租户独立预算
|
||||
assert _put_push_group(super_client, "other", {
|
||||
**PUSH_GROUP, "prefix": "other-p"}).status_code == 200
|
||||
r = _post_test(super_client, "other")
|
||||
assert r.status_code == 200
|
||||
|
||||
|
||||
def test_push_test_auth_matrix(super_client, monkeypatch):
|
||||
"""require_tenant(slug): 本租户管理员放行;跨租户 403;未认证 401。"""
|
||||
_create(super_client, slug="jc2", admin="jc2-admin", password="jc2-pass-1")
|
||||
|
||||
Reference in New Issue
Block a user