feat: add realtime challenge client and local smoke test
CI / test (pull_request) Successful in 2m53s
PR合并自动部署 / release-check (pull_request) Successful in 1m34s
PR合并自动部署 / deploy (pull_request) Successful in 12s

This commit is contained in:
2026-08-09 03:08:01 +08:00
parent 821311f4ad
commit 1dd828609e
9 changed files with 872 additions and 7 deletions
+132
View File
@@ -0,0 +1,132 @@
# 本地实时 1v1 与联机码约战测试
本指南用于在一台电脑上使用两个浏览器会话验证完整联机流程。
## 1. 准备数据
```bash
make install
make migrate
make seed
```
种子数据会创建三个赛道的实时 1v1 比赛。本地邀请码为:
```text
HULU2026
```
## 2. 使用 ASGI 启动
实时比赛依赖 WebSocket。不要使用普通 WSGI 服务测试联机。
```bash
make run-asgi
```
访问:
```text
http://127.0.0.1:8000/
```
本地没有配置 `REDIS_URL` 时会使用进程内 Channel Layer,适合单进程开发测试。生产环境必须使用 Redis。
### 一键端到端验证
保持 `make run-asgi` 运行,另开终端执行:
```bash
.venv/bin/python scripts/test_realtime_local.py
```
脚本会临时创建两个本地账号,通过真实 HTTP Session 和两个真实 WebSocket 完成:
```text
创建联机码
→ 第二位玩家加入
→ matched 状态推送
→ 答题进度同步
→ 第一位提交且不泄露答案
→ 第二位提交
→ completed 推送
→ 胜负、Rating 和解析检查
```
结束后脚本自动清理临时用户和比赛记录。
## 3. 准备两个独立登录会话
使用下列任一组合:
- Chrome 普通窗口 + 无痕窗口
- Chrome + Safari
- 两个不同浏览器 Profile
两个窗口分别使用邀请码 `HULU2026` 注册不同账号。不要在同一浏览器 Profile 的两个普通标签页登录不同账号,因为它们会共享 Session Cookie。
## 4. 联机码约战
玩家 A
1. 打开“比赛”。
2. 选择双方约定的赛道。
3. 点击“创建当前赛道约战”。
4. 复制 6 位联机码。
玩家 B
1. 打开“比赛”。
2. 输入联机码。
3. 点击“加入约战”。
预期结果:
- 玩家 A 无需再次点击,自动进入答题。
- 双方显示相同题目和同一个倒计时。
- 任一方填写答案时,另一方看到答题数量变化。
- 第一位提交者只看到“答案已锁定”,看不到正确答案。
- 双方提交或倒计时结束后,同时展示胜负、双方分数、Rating 变化和题目解析。
## 5. 随机匹配
双方选择同一赛道并点击“开始匹配”。
预期结果:
- 第一位玩家进入等待状态。
- 第二位玩家加入后,第一位玩家自动进入答题。
- 私人联机码房间不会被随机匹配玩家加入。
## 6. 断线与超时
验证以下场景:
1. 答题时短暂关闭网络,再恢复。
2. WebSocket 断开后页面仍每 2 秒轮询比赛状态。
3. 关闭其中一个窗口,另一方等待倒计时结束。
4. 服务端到时后将未提交 Attempt 标记为过期并完成结算。
5. 等待中的联机码 10 分钟后失效。
## 7. 排查
浏览器开发者工具应看到:
```text
WS /ws/v1/contest/matches/<match_id>/
GET /api/v1/contests/matches/<match_id>/
```
检查 Redis
```bash
redis-cli ping
```
检查 ASGI
```bash
curl http://127.0.0.1:8000/health/
```
生产 Nginx 必须为 `/ws/` 设置 `Upgrade``Connection` 请求头。详见 `docs/DEPLOYMENT.md`