交易服务收敛为仅 rakuten:移除 rakuma 登录态与下单入口
trading 不再管理 ラクマ 的购物车购买、支付与订单监控。删除 auth_site / auth_session / login_runner / models.AuthSite 中的 rakuma 分支与常量、 account.yaml.example 的 rakuma 段,并清理相关测试。scraping 侧的 ラクマ 抓取 API(/api/rakuma/*)保留不动。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -22,8 +22,6 @@ from app.trading.services.auth_session import AuthSession
|
||||
CART_LOGGED_OUT = f"<html><body>買い物かご {auth_site.RAKUTEN_LOGGED_OUT_MARKER}</body></html>"
|
||||
CART_LOGGED_IN = "<html><body>買い物かご 商品が1点入っています</body></html>"
|
||||
|
||||
MYPAGE_HTML = "<html><body>マイページ</body></html>"
|
||||
|
||||
|
||||
def make_settings(tmp_path: Path, **overrides) -> Settings:
|
||||
base = {
|
||||
@@ -45,7 +43,7 @@ def write_state(settings: Settings, site: str, cookies: list[dict]) -> Path:
|
||||
|
||||
|
||||
async def build_session(settings: Settings, handler) -> AuthSession:
|
||||
"""构建 AuthSession 并把两站 client 换成 MockTransport 版本
|
||||
"""构建 AuthSession 并把 client 换成 MockTransport 版本
|
||||
|
||||
换掉 client 会丢掉 start() 时灌进去的 cookie,因此重新走一次 reload
|
||||
把登录态读回新客户端;reload 同时清空探测缓存,正好是测试想要的干净起点。
|
||||
@@ -79,8 +77,6 @@ async def test_loads_cookies_from_state_file(tmp_path):
|
||||
try:
|
||||
names = {c.name for c in session.client("rakuten").cookies.jar}
|
||||
assert "SESSION" in names
|
||||
# 没有 state 文件的那一站应为空,而不是报错
|
||||
assert not list(session.client("rakuma").cookies.jar)
|
||||
finally:
|
||||
await session.close()
|
||||
|
||||
@@ -139,38 +135,6 @@ async def test_rakuten_detects_logged_in(tmp_path):
|
||||
await session.close()
|
||||
|
||||
|
||||
async def test_rakuma_detects_logged_out_by_redirect(tmp_path):
|
||||
"""/mypage 被重定向到登录页即判定未登录
|
||||
|
||||
ラクマ 未登录时返回 302 而非改文案,因此判据是落地 URL 不是页面内容。
|
||||
"""
|
||||
settings = make_settings(tmp_path)
|
||||
|
||||
def handler(request: httpx.Request) -> httpx.Response:
|
||||
if request.url.path == "/mypage":
|
||||
return httpx.Response(302, headers={"Location": auth_site.RAKUMA_LOGIN_URL})
|
||||
return httpx.Response(200, text="<html>ログイン</html>")
|
||||
|
||||
session = await build_session(settings, handler)
|
||||
try:
|
||||
status = await session.check("rakuma")
|
||||
assert status.logged_in is False
|
||||
assert "登录页" in status.detail
|
||||
finally:
|
||||
await session.close()
|
||||
|
||||
|
||||
async def test_rakuma_detects_logged_in(tmp_path):
|
||||
"""/mypage 正常返回即判定已登录"""
|
||||
settings = make_settings(tmp_path)
|
||||
session = await build_session(settings, lambda r: httpx.Response(200, text=MYPAGE_HTML))
|
||||
try:
|
||||
status = await session.check("rakuma")
|
||||
assert status.logged_in is True
|
||||
finally:
|
||||
await session.close()
|
||||
|
||||
|
||||
async def test_error_status_counts_as_logged_out(tmp_path):
|
||||
"""探测页返回 4xx/5xx 时保守判定为未登录,不放行下单"""
|
||||
settings = make_settings(tmp_path)
|
||||
|
||||
@@ -27,7 +27,7 @@ class StubAuthSession:
|
||||
|
||||
@property
|
||||
def sites(self) -> tuple[str, ...]:
|
||||
return ("rakuten", "rakuma")
|
||||
return ("rakuten",)
|
||||
|
||||
def _status(self, site: str) -> AuthStatus:
|
||||
return AuthStatus(
|
||||
@@ -87,7 +87,7 @@ def test_health_needs_no_token(client):
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
assert body["data"]["status"] == "ok"
|
||||
assert set(body["data"]["auth"]) == {"rakuten", "rakuma"}
|
||||
assert set(body["data"]["auth"]) == {"rakuten"}
|
||||
|
||||
|
||||
def test_health_does_not_probe_the_site(client, stub):
|
||||
@@ -116,12 +116,12 @@ def test_auth_endpoints_reject_wrong_token(client):
|
||||
# ---- 登录态查询 ----
|
||||
|
||||
|
||||
def test_status_probes_both_sites_by_default(client, stub):
|
||||
def test_status_probes_site_by_default(client, stub):
|
||||
response = client.post("/api/auth/status", json={}, headers=AUTH)
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
assert [item["site"] for item in body["data"]["sites"]] == ["rakuten", "rakuma"]
|
||||
assert stub.checked == ["rakuten", "rakuma"]
|
||||
assert [item["site"] for item in body["data"]["sites"]] == ["rakuten"]
|
||||
assert stub.checked == ["rakuten"]
|
||||
|
||||
|
||||
def test_status_can_skip_the_probe(client, stub):
|
||||
@@ -132,9 +132,9 @@ def test_status_can_skip_the_probe(client, stub):
|
||||
|
||||
|
||||
def test_status_accepts_a_single_site(client, stub):
|
||||
response = client.post("/api/auth/status", json={"site": "rakuma"}, headers=AUTH)
|
||||
response = client.post("/api/auth/status", json={"site": "rakuten"}, headers=AUTH)
|
||||
assert response.status_code == 200
|
||||
assert stub.checked == ["rakuma"]
|
||||
assert stub.checked == ["rakuten"]
|
||||
|
||||
|
||||
def test_status_rejects_unknown_site(client):
|
||||
|
||||
@@ -252,11 +252,11 @@ async def test_unimplemented_site_interaction_becomes_needs_human(
|
||||
assert "未实现" in terminal["detail"]
|
||||
|
||||
|
||||
# ---- ラクマ 不实现 → needs_human ----
|
||||
# ---- ラクマ 不在交易范围 → needs_human ----
|
||||
|
||||
|
||||
async def test_rakuma_site_reports_needs_human(runner: WorkerRunner):
|
||||
"""首版只对乐天;其他站点直接转人工"""
|
||||
"""交易服务只对乐天;其他站点(含 ラクマ)直接转人工"""
|
||||
await runner.handle(_make_task(task_id="t1", site="rakuma"))
|
||||
|
||||
gateway: FakeGateway = runner._gateway_for_test # type: ignore[attr-defined]
|
||||
|
||||
Reference in New Issue
Block a user