fix(sync): 限流检测漏掉了它真实的样子

上一版加了 429 识别,但点同步按钮报的还是 JSONDecodeError——因为检测
只看 `e.response.status_code` 和异常消息,而真实到达我们手里的异常两样
都不满足:garth 对着 429 调 .json(),抛出的 JSONDecodeError 里状态码已经
丢了,消息是无用的 "Expecting value: line 1 column 1"。

响应体「Rate limited」唯一幸存的地方是异常的 `doc` 属性,改为从那里取。

同时改正上一版的测试:它用 ValueError("Rate limited") 构造,那个形态现实中
根本不会出现,所以测试通过、检测却漏掉了每一个真实的限流。现在用真的
json.JSONDecodeError 构造,并先断言「光看消息不够」。

实测同步现在返回:
  RateLimited: Garmin 暂时限制了请求频率…令牌本身没有失效

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
ericwyuan
2026-08-28 14:27:15 +08:00
parent 042c4d52be
commit a4bedc263f
2 changed files with 21 additions and 4 deletions

View File

@@ -619,8 +619,16 @@ class TestRateLimiting:
def teardown_method(self):
garmin_svc._rate_limited_until.clear()
def test_plain_text_body_is_recognised(self):
assert garmin_svc._is_rate_limited(ValueError("Rate limited"))
def test_the_real_shape_is_recognised(self):
"""garth calls .json() on the 429, so what actually reaches us is a
JSONDecodeError whose message says nothing and whose `doc` holds the
body. An earlier version of this test asserted on a hand-made
ValueError("Rate limited") — a shape that never occurs — and passed
while the detector missed every real one."""
import json
err = json.JSONDecodeError("Expecting value", "Rate limited", 0)
assert "rate limit" not in str(err).lower(), "the message alone is not enough"
assert garmin_svc._is_rate_limited(err)
def test_status_code_is_recognised(self):
class Resp: