feat(sms): verify_code try-both 遍历启用的 fallback 链
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -56,5 +56,17 @@ def send_code(phone: str) -> SendResult:
|
||||
|
||||
|
||||
def verify_code(phone: str, code: str) -> bool:
|
||||
"""校验:委托当前主 provider(try-both 在 Task 5 加)。"""
|
||||
return _primary().verify_code(phone, code)
|
||||
"""校验:try-both,遍历「启用的 fallback 链」(主→备),任一命中即 True。
|
||||
|
||||
码只存在实际发码那家(fallback 前主已 pop 掉自己的码),另一家 rec is None 即 False、
|
||||
不误判、不累加其防爆破计数。关闭 fallback 时链中只有主,备完全不参与。
|
||||
"""
|
||||
chain = [_primary()]
|
||||
fb = _fallback()
|
||||
if fb is not None:
|
||||
chain.append(fb)
|
||||
for prov in chain:
|
||||
if prov.verify_code(phone, code): # Mode B:纯本地内存比对,不联网
|
||||
logger.info("[SMS] verify hit provider=%s", _NAME[prov])
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -92,3 +92,51 @@ def test_send_code_backup_also_fails_raises_backup_error(monkeypatch):
|
||||
with pytest.raises(SmsError) as ei:
|
||||
sms.send_code(PHONE)
|
||||
assert "创蓝" in str(ei.value)
|
||||
|
||||
|
||||
def test_verify_hits_primary_without_touching_backup(monkeypatch):
|
||||
calls = []
|
||||
monkeypatch.setattr(settings, "SMS_PROVIDER", "jiguang")
|
||||
monkeypatch.setattr(settings, "SMS_FALLBACK_PROVIDER", "chuanglan")
|
||||
monkeypatch.setattr(jiguang, "verify_code",
|
||||
lambda p, c: (calls.append("jiguang"), True)[1])
|
||||
monkeypatch.setattr(chuanglan, "verify_code",
|
||||
lambda p, c: (calls.append("chuanglan"), True)[1])
|
||||
|
||||
assert sms.verify_code(PHONE, "123456") is True
|
||||
assert calls == ["jiguang"]
|
||||
|
||||
|
||||
def test_verify_falls_through_to_backup(monkeypatch):
|
||||
calls = []
|
||||
monkeypatch.setattr(settings, "SMS_PROVIDER", "jiguang")
|
||||
monkeypatch.setattr(settings, "SMS_FALLBACK_PROVIDER", "chuanglan")
|
||||
monkeypatch.setattr(jiguang, "verify_code",
|
||||
lambda p, c: (calls.append("jiguang"), False)[1])
|
||||
monkeypatch.setattr(chuanglan, "verify_code",
|
||||
lambda p, c: (calls.append("chuanglan"), True)[1])
|
||||
|
||||
assert sms.verify_code(PHONE, "123456") is True
|
||||
assert calls == ["jiguang", "chuanglan"]
|
||||
|
||||
|
||||
def test_verify_all_miss_returns_false(monkeypatch):
|
||||
monkeypatch.setattr(settings, "SMS_PROVIDER", "jiguang")
|
||||
monkeypatch.setattr(settings, "SMS_FALLBACK_PROVIDER", "chuanglan")
|
||||
monkeypatch.setattr(jiguang, "verify_code", lambda p, c: False)
|
||||
monkeypatch.setattr(chuanglan, "verify_code", lambda p, c: False)
|
||||
|
||||
assert sms.verify_code(PHONE, "123456") is False
|
||||
|
||||
|
||||
def test_verify_backup_not_touched_when_fallback_off(monkeypatch):
|
||||
calls = []
|
||||
monkeypatch.setattr(settings, "SMS_PROVIDER", "jiguang")
|
||||
monkeypatch.setattr(settings, "SMS_FALLBACK_PROVIDER", "")
|
||||
monkeypatch.setattr(jiguang, "verify_code",
|
||||
lambda p, c: (calls.append("jiguang"), False)[1])
|
||||
monkeypatch.setattr(chuanglan, "verify_code",
|
||||
lambda p, c: (calls.append("chuanglan"), True)[1])
|
||||
|
||||
assert sms.verify_code(PHONE, "123456") is False
|
||||
assert calls == ["jiguang"]
|
||||
|
||||
Reference in New Issue
Block a user