test: 全面迁移 pytest 并加入格式门禁
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
"""虎牙 App 密码登录及相关组件测试。"""
|
||||
|
||||
import pytest
|
||||
|
||||
import base64
|
||||
import os
|
||||
import struct
|
||||
import unittest
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
@@ -32,16 +33,18 @@ from core.huya.wup_encoder import build_password_login_wup
|
||||
|
||||
from web.backend.database import Base
|
||||
from web.backend.models import User, HuyaAccount
|
||||
from web.backend.schemas import HuyaAppPasswordLoginRequest, HuyaPasswordLoginSelectedRequest
|
||||
from web.backend.schemas import (
|
||||
HuyaAppPasswordLoginRequest,
|
||||
HuyaPasswordLoginSelectedRequest,
|
||||
)
|
||||
from web.backend.routers.huya import (
|
||||
app_password_login_account,
|
||||
app_password_login_selected_accounts,
|
||||
)
|
||||
|
||||
|
||||
class TestHuyaAppLogin(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
class TestHuyaAppLogin:
|
||||
def setup_method(self):
|
||||
self.engine = create_engine("sqlite://")
|
||||
Base.metadata.create_all(self.engine)
|
||||
self.session = sessionmaker(bind=self.engine)()
|
||||
@@ -49,7 +52,7 @@ class TestHuyaAppLogin(unittest.TestCase):
|
||||
self.session.add(self.admin)
|
||||
self.session.commit()
|
||||
|
||||
def tearDown(self):
|
||||
def teardown_method(self):
|
||||
self.session.close()
|
||||
Base.metadata.drop_all(self.engine)
|
||||
self.engine.dispose()
|
||||
@@ -59,54 +62,54 @@ class TestHuyaAppLogin(unittest.TestCase):
|
||||
plain = b"Hello, Huya App Login Protocol!"
|
||||
enc = udb_encrypt(key, plain)
|
||||
dec = udb_decrypt(key, enc)
|
||||
self.assertEqual(dec, plain)
|
||||
assert dec == plain
|
||||
|
||||
def test_cert_and_nonce_forge(self):
|
||||
uid = 1199666914671
|
||||
rnd = gen_nonce(uid, K1_DEFAULT)
|
||||
self.assertEqual(len(rnd), 20)
|
||||
assert len(rnd) == 20
|
||||
|
||||
fp = b"02df398797432eadefcc12767119ad5e80999389"
|
||||
cred = b"\x0a" + os.urandom(113)
|
||||
p1 = build_p1(b"5008", fp, cred, rnd=rnd)
|
||||
self.assertEqual(len(p1), 187)
|
||||
assert len(p1) == 187
|
||||
|
||||
cert = forge_cert(p1)
|
||||
dec = decrypt_cert(cert)
|
||||
parsed = parse_p1(dec)
|
||||
self.assertEqual(parsed["rnd"], rnd)
|
||||
self.assertEqual(parsed["fingerprint"], fp)
|
||||
self.assertEqual(parsed["cred"], cred)
|
||||
assert parsed["rnd"] == rnd
|
||||
assert parsed["fingerprint"] == fp
|
||||
assert parsed["cred"] == cred
|
||||
|
||||
def test_envelope_patching(self):
|
||||
env = Envelope.load()
|
||||
self.assertGreater(env.uid, 0)
|
||||
self.assertEqual(len(env.cert_b64), 260)
|
||||
assert env.uid > 0
|
||||
assert len(env.cert_b64) == 260
|
||||
|
||||
new_uid = 1199666911746
|
||||
env.patch_uid(new_uid)
|
||||
self.assertEqual(env.uid, new_uid)
|
||||
assert env.uid == new_uid
|
||||
|
||||
fake_cert = bytes([0x0C, 0x20]) + os.urandom(192)
|
||||
env.patch_cert(fake_cert)
|
||||
self.assertEqual(len(env.cert_b64), 260)
|
||||
assert len(env.cert_b64) == 260
|
||||
|
||||
wup_b64 = env.wup_b64()
|
||||
self.assertGreater(len(wup_b64), 0)
|
||||
assert len(wup_b64) > 0
|
||||
|
||||
def test_device_profile_generation(self):
|
||||
p1 = generate_profile()
|
||||
self.assertEqual(p1["os"], "android")
|
||||
self.assertEqual(len(p1["fingerprint"]), 40)
|
||||
self.assertEqual(len(p1["device_id"]), 40)
|
||||
self.assertEqual(p1["hdid"], "ed0db8334cadd236c00cadf7e11ab5a5")
|
||||
assert p1["os"] == "android"
|
||||
assert len(p1["fingerprint"]) == 40
|
||||
assert len(p1["device_id"]) == 40
|
||||
assert p1["hdid"] == "ed0db8334cadd236c00cadf7e11ab5a5"
|
||||
# 画像不再承载 safedeviceid:该令牌由 dfp_register 注册链每次登录前签发
|
||||
self.assertNotIn("safedeviceid", p1)
|
||||
self.assertNotIn("safedeviceid", DEFAULT_GOLDEN_DEV)
|
||||
assert "safedeviceid" not in p1
|
||||
assert "safedeviceid" not in DEFAULT_GOLDEN_DEV
|
||||
|
||||
p2 = get_profile("test_user_account_123")
|
||||
p3 = get_profile("test_user_account_123")
|
||||
self.assertEqual(p2["fingerprint"], p3["fingerprint"])
|
||||
assert p2["fingerprint"] == p3["fingerprint"]
|
||||
|
||||
def test_wup_encoder_output(self):
|
||||
dev = generate_profile()
|
||||
@@ -121,18 +124,22 @@ class TestHuyaAppLogin(unittest.TestCase):
|
||||
user_action_json="{}",
|
||||
device_info=dev,
|
||||
)
|
||||
self.assertGreater(len(pkt), 500)
|
||||
assert len(pkt) > 500
|
||||
total_len = struct.unpack(">I", pkt[:4])[0]
|
||||
self.assertEqual(total_len, len(pkt))
|
||||
assert total_len == len(pkt)
|
||||
|
||||
# ---- 新设备注册链 (core/huya/dfp_register) 生产接入测试 ----
|
||||
|
||||
def test_wup_login_skips_registration_when_safedeviceid_given(self):
|
||||
"""显式传入 safedeviceid 时不再触发注册链(风控重试复用同一注册结果)。"""
|
||||
with patch("core.huya.app_login.register_device") as m_reg, \
|
||||
patch("core.huya.app_login.build_password_login_wup", return_value=b"pkt"), \
|
||||
patch("core.huya.app_login.requests.post",
|
||||
return_value=MagicMock(status_code=200, content=b"")):
|
||||
with (
|
||||
patch("core.huya.app_login.register_device") as m_reg,
|
||||
patch("core.huya.app_login.build_password_login_wup", return_value=b"pkt"),
|
||||
patch(
|
||||
"core.huya.app_login.requests.post",
|
||||
return_value=MagicMock(status_code=200, content=b""),
|
||||
),
|
||||
):
|
||||
wup_password_login_raw("300023887", "pw", safedeviceid="A" * 180)
|
||||
m_reg.assert_not_called()
|
||||
|
||||
@@ -146,37 +153,48 @@ class TestHuyaAppLogin(unittest.TestCase):
|
||||
captured["args"] = args
|
||||
return b"pkt"
|
||||
|
||||
with patch("core.huya.app_login.register_device",
|
||||
return_value=("a" * 32, new_action, new_device_id)) as m_reg, \
|
||||
patch("core.huya.app_login.build_password_login_wup", side_effect=fake_build), \
|
||||
patch("core.huya.app_login.requests.post",
|
||||
return_value=MagicMock(status_code=200, content=b"")):
|
||||
with (
|
||||
patch(
|
||||
"core.huya.app_login.register_device",
|
||||
return_value=("a" * 32, new_action, new_device_id),
|
||||
) as m_reg,
|
||||
patch(
|
||||
"core.huya.app_login.build_password_login_wup", side_effect=fake_build
|
||||
),
|
||||
patch(
|
||||
"core.huya.app_login.requests.post",
|
||||
return_value=MagicMock(status_code=200, content=b""),
|
||||
),
|
||||
):
|
||||
wup_password_login_raw("300023887", "pw")
|
||||
m_reg.assert_called_once()
|
||||
# args: uid_str, sha1, safedeviceid, hdid, session, traceId, ua, dev
|
||||
self.assertEqual(captured["args"][2], new_action)
|
||||
self.assertEqual(captured["args"][7]["device_id"], new_device_id)
|
||||
assert captured["args"][2] == new_action
|
||||
assert captured["args"][7]["device_id"] == new_device_id
|
||||
# 画像默认值里的旧 device_id 被注册结果覆盖,而非沿用
|
||||
self.assertNotEqual(
|
||||
captured["args"][7]["device_id"],
|
||||
DEFAULT_GOLDEN_DEV["device_id"],
|
||||
)
|
||||
assert captured["args"][7]["device_id"] != DEFAULT_GOLDEN_DEV["device_id"]
|
||||
|
||||
def test_wup_login_registration_failure_is_explicit(self):
|
||||
"""注册失败必须抛错终止,禁止静默回退旧链(不发任何登录请求)。"""
|
||||
with patch("core.huya.app_login.register_device",
|
||||
side_effect=DfpRegistrationError("注册链超时")) as m_reg, \
|
||||
patch("core.huya.app_login.requests.post") as m_post:
|
||||
with self.assertRaises(HuyaAppLoginError):
|
||||
with (
|
||||
patch(
|
||||
"core.huya.app_login.register_device",
|
||||
side_effect=DfpRegistrationError("注册链超时"),
|
||||
) as m_reg,
|
||||
patch("core.huya.app_login.requests.post") as m_post,
|
||||
):
|
||||
with pytest.raises(HuyaAppLoginError):
|
||||
wup_password_login_raw("300023887", "pw")
|
||||
m_reg.assert_called_once()
|
||||
m_post.assert_not_called()
|
||||
|
||||
def test_login_cred_flow_registration_failure_is_explicit(self):
|
||||
"""login_cred_with_flow 注册失败同样包装为 HuyaAppLoginError 显式失败。"""
|
||||
with patch("core.huya.app_login.register_device",
|
||||
side_effect=DfpRegistrationError("注册链 HTTP 500")):
|
||||
with self.assertRaisesRegex(HuyaAppLoginError, "注册失败"):
|
||||
with patch(
|
||||
"core.huya.app_login.register_device",
|
||||
side_effect=DfpRegistrationError("注册链 HTTP 500"),
|
||||
):
|
||||
with pytest.raises(HuyaAppLoginError, match="注册失败"):
|
||||
login_cred_with_flow("300023887", "pw")
|
||||
|
||||
def test_router_functions(self):
|
||||
@@ -187,26 +205,32 @@ class TestHuyaAppLogin(unittest.TestCase):
|
||||
sdid="mock_sdid_123",
|
||||
)
|
||||
|
||||
with patch("web.backend.routers.huya.login_huya_app_password", return_value=mock_res):
|
||||
with patch(
|
||||
"web.backend.routers.huya.login_huya_app_password", return_value=mock_res
|
||||
):
|
||||
req = HuyaAppPasswordLoginRequest(
|
||||
username="mock_test_huya_user",
|
||||
password="mock_password_123",
|
||||
tag="test_tag",
|
||||
)
|
||||
resp = app_password_login_account(req=req, db=self.session, current=self.admin)
|
||||
self.assertTrue(resp["success"])
|
||||
self.assertIn("App", resp["message"])
|
||||
self.assertEqual(resp["account"].username, "mock_test_huya_user")
|
||||
resp = app_password_login_account(
|
||||
req=req, db=self.session, current=self.admin
|
||||
)
|
||||
assert resp["success"]
|
||||
assert "App" in resp["message"]
|
||||
assert resp["account"].username == "mock_test_huya_user"
|
||||
|
||||
# Test batch app login router function
|
||||
acc = self.session.query(HuyaAccount).filter(HuyaAccount.username == "mock_test_huya_user").first()
|
||||
acc = (
|
||||
self.session.query(HuyaAccount)
|
||||
.filter(HuyaAccount.username == "mock_test_huya_user")
|
||||
.first()
|
||||
)
|
||||
batch_req = HuyaPasswordLoginSelectedRequest(account_ids=[acc.id])
|
||||
batch_resp = app_password_login_selected_accounts(req=batch_req, db=self.session, current=self.admin)
|
||||
self.assertTrue(batch_resp["success"])
|
||||
self.assertEqual(batch_resp["count"], 1)
|
||||
self.assertEqual(len(batch_resp["results"]), 1)
|
||||
self.assertTrue(batch_resp["results"][0]["success"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
batch_resp = app_password_login_selected_accounts(
|
||||
req=batch_req, db=self.session, current=self.admin
|
||||
)
|
||||
assert batch_resp["success"]
|
||||
assert batch_resp["count"] == 1
|
||||
assert len(batch_resp["results"]) == 1
|
||||
assert batch_resp["results"][0]["success"]
|
||||
|
||||
Reference in New Issue
Block a user