Merge branch 'fix/pyright-env-and-type-guards' into dev
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
"""虎牙「短信接码一键登录」端点:调用契约与成功/失败两条分支。
|
||||
|
||||
背景(这是本文件的**存在理由**,别删):该端点曾引用一个从来不存在的
|
||||
``core.huya.auto_register.auto_register_huya_phone``(git 全历史都没有 ``def``),
|
||||
所以每次调用都在 import 阶段抛 ``ImportError`` → HTTP 500,且因为导入写在函数体
|
||||
内部,静态检查之外没有任何东西拦得住它。用例锁死「端点必须调用真实存在的
|
||||
``register_huya_with_sms_line``」这个契约,名字再被改就不会静默回归。
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from fastapi import HTTPException
|
||||
|
||||
from core.huya.auto_register import HuyaAutoRegisterResult
|
||||
from tests.support.db import get_test_engine, make_test_session
|
||||
from web.backend.models import HuyaAccount, User
|
||||
from web.backend.routers.huya.login import auto_sms_login_account
|
||||
|
||||
# 能被 parse_huya_cookie_line 认出来的最小虎牙 CK(含 yyuid= / udb_uid=)。
|
||||
LOGIN_COOKIE = "yyuid=100; udb_uid=100"
|
||||
|
||||
|
||||
def _ok_result(item, **kwargs):
|
||||
return HuyaAutoRegisterResult(
|
||||
phone=item.phone,
|
||||
provider=item.provider,
|
||||
success=True,
|
||||
status="success",
|
||||
message="接码成功",
|
||||
cookie=LOGIN_COOKIE,
|
||||
)
|
||||
|
||||
|
||||
class TestAutoSmsLoginAccount:
|
||||
def setup_method(self):
|
||||
self.engine = get_test_engine()
|
||||
self.session = make_test_session(self.engine)
|
||||
self.user = User(username="operator", password_hash="hash", role="super_admin")
|
||||
self.account = HuyaAccount(
|
||||
uid="",
|
||||
yyuid="",
|
||||
cookie="",
|
||||
game_phone="13800000000",
|
||||
sms_url="https://sms.example.com/get?p=1",
|
||||
)
|
||||
self.session.add_all([self.user, self.account])
|
||||
self.session.commit()
|
||||
|
||||
def teardown_method(self):
|
||||
self.session.close()
|
||||
|
||||
def _call(self):
|
||||
return auto_sms_login_account(
|
||||
self.account.id, db=self.session, current=self.user
|
||||
)
|
||||
|
||||
def test_calls_existing_register_helper_and_saves_cookie(self, monkeypatch):
|
||||
"""核心契约:必须调用真实存在的注册函数,并把返回的 CK 回填落库。"""
|
||||
calls: dict = {}
|
||||
|
||||
def fake_register(item, **kwargs):
|
||||
calls["item"] = item
|
||||
calls["kwargs"] = kwargs
|
||||
return _ok_result(item, **kwargs)
|
||||
|
||||
# 用字符串形式 patch 目标模块属性:端点内部是 `from ... import ...`,
|
||||
# 每次调用都会重新取模块属性,所以这层 patch 必须生效。
|
||||
monkeypatch.setattr(
|
||||
"core.huya.auto_register.register_huya_with_sms_line", fake_register
|
||||
)
|
||||
|
||||
out = self._call()
|
||||
|
||||
assert out["success"] is True
|
||||
# 断言序列化结果,不看属性(AGENTS.md 坑 #2)
|
||||
assert out["account"].model_dump()["uid"] == "100"
|
||||
assert calls["item"].phone == "13800000000"
|
||||
assert calls["item"].url == "https://sms.example.com/get?p=1"
|
||||
# 超时/轮询间隔是端点的既有行为,不能被顺手改掉
|
||||
assert calls["kwargs"]["wait_seconds"] == 90
|
||||
assert calls["kwargs"]["poll_interval"] == 2
|
||||
|
||||
self.session.refresh(self.account)
|
||||
assert self.account.status == "active"
|
||||
assert self.account.login_channel == "sms"
|
||||
assert "udb_uid=100" in self.account.cookie
|
||||
|
||||
def test_failure_marks_account_login_failed(self, monkeypatch):
|
||||
"""注册失败要落库成 login_failed 并返回 502,而不是假装成功。"""
|
||||
|
||||
def fake_register(item, **kwargs):
|
||||
return HuyaAutoRegisterResult(
|
||||
phone=item.phone,
|
||||
provider=item.provider,
|
||||
success=False,
|
||||
status="failed",
|
||||
message="接码平台超时",
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
"core.huya.auto_register.register_huya_with_sms_line", fake_register
|
||||
)
|
||||
|
||||
with pytest.raises(HTTPException) as excinfo:
|
||||
self._call()
|
||||
|
||||
assert excinfo.value.status_code == 502
|
||||
assert "接码平台超时" in str(excinfo.value.detail)
|
||||
|
||||
self.session.refresh(self.account)
|
||||
assert self.account.status == "login_failed"
|
||||
|
||||
def test_missing_phone_or_sms_url_is_rejected_before_import(self):
|
||||
"""缺手机号/接码链接要在调用注册前 400,不能先崩在 import 上。"""
|
||||
self.account.game_phone = ""
|
||||
self.session.commit()
|
||||
|
||||
with pytest.raises(HTTPException) as excinfo:
|
||||
self._call()
|
||||
|
||||
assert excinfo.value.status_code == 400
|
||||
@@ -1,3 +1,5 @@
|
||||
import io
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from core.huya import browser_harvest
|
||||
@@ -51,3 +53,50 @@ def test_launch_can_show_window_when_requested(monkeypatch):
|
||||
browser_harvest.launch(Path("/tmp/test-huya-profile"), 9556, headless=False)
|
||||
|
||||
assert "--headless=new" not in calls[0]
|
||||
|
||||
|
||||
def test_launch_prefers_page_target_over_browser_endpoint(monkeypatch):
|
||||
"""页面级 ws 必须优先于 browser 级(Network 域只能挂在 page target 上)。
|
||||
|
||||
这里原本写的是 ``pages[0]``,而 ``pages`` 是集合推导出来的 **set** ——
|
||||
``set`` 不可下标,抛出的 TypeError 又被外层 ``except Exception: pass``
|
||||
吞掉,于是每次都退回 browser 级 endpoint:页面级探测**从来没有成功过一次**,
|
||||
而且没有任何日志能看出来。这就是本用例存在的意义。
|
||||
"""
|
||||
page_ws = "ws://127.0.0.1/devtools/page/PAGE"
|
||||
browser_ws = "ws://127.0.0.1/devtools/browser/test"
|
||||
payload = json.dumps([{"type": "page", "webSocketDebuggerUrl": page_ws}])
|
||||
|
||||
monkeypatch.setattr(
|
||||
browser_harvest.subprocess, "Popen", lambda args, **kwargs: _FakeProcess()
|
||||
)
|
||||
# _FakeProcess.stderr 会给出 browser 级 endpoint,用来证明「选中了页面级」
|
||||
monkeypatch.setattr(
|
||||
browser_harvest.urllib.request,
|
||||
"urlopen",
|
||||
lambda *args, **kwargs: io.StringIO(payload),
|
||||
)
|
||||
|
||||
_proc, ws_url = browser_harvest.launch(Path("/tmp/test-huya-profile"), 9557)
|
||||
|
||||
assert ws_url == page_ws
|
||||
assert ws_url != browser_ws
|
||||
|
||||
|
||||
def test_launch_falls_back_to_browser_endpoint_without_page_target(monkeypatch):
|
||||
"""没有 page target 时才允许退回 browser 级 endpoint。"""
|
||||
browser_ws = "ws://127.0.0.1/devtools/browser/test"
|
||||
payload = json.dumps([{"type": "service_worker", "webSocketDebuggerUrl": "ws://x"}])
|
||||
|
||||
monkeypatch.setattr(
|
||||
browser_harvest.subprocess, "Popen", lambda args, **kwargs: _FakeProcess()
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
browser_harvest.urllib.request,
|
||||
"urlopen",
|
||||
lambda *args, **kwargs: io.StringIO(payload),
|
||||
)
|
||||
|
||||
_proc, ws_url = browser_harvest.launch(Path("/tmp/test-huya-profile"), 9558)
|
||||
|
||||
assert ws_url == browser_ws
|
||||
|
||||
Reference in New Issue
Block a user