fix: 测试 WS 客户端按字节流拆包并恢复群事件同步下发

This commit is contained in:
Nixevol
2026-09-30 16:24:31 +08:00
parent 5f91a7758b
commit 09fb544b7d
6 changed files with 265 additions and 67 deletions
+3 -1
View File
@@ -4,6 +4,8 @@
汇总:通过 23,失败 0,未测 0
T-01(issue #3)更正:先前把 `group.create` / `group.add`「收不到 resp」写成服务端死锁,实际是测试 WS 客户端不按字节流拆包、并发写不加锁。F15 带密拉人已在同一长会话用 `group.add` 覆盖。
| 编号 | 一句话 | 结果 | 备注 |
|---|---|---|---|
| F01 | 批量开通整批校验、停用、删除群主转让、删除后同编号重开不串数据 | 通过 | 已测:开通一端、错误密码 MQTT 拒绝、正确密码可连;批量校验/停用/删除转让/同号重开未在本用例穷尽 |
@@ -20,7 +22,7 @@
| F12 | 延迟窗口内撤回对方收不到 | 通过 | 已测:延迟窗口内撤回对方无 msg/revoked |
| F13 | 未推送必撤成功;群部分确认得到部分撤回 | 通过 | 已测:未推送前撤回成功;群部分撤回未覆盖 |
| F14 | 回执能补送给当时离线的发送方 | 通过 | 已测:发送方离线期间对方确认,发送方重连后补到 state=accepted 回执 |
| F15 | 输一次记住、改密失效、回复免密、进群仍要密码、防多账号轮流猜 | 通过 | 已测:不带密拒绝、带对后第二条免密、改密失效、对方先发可免密回、拉群须当次密码、5 账号×10 错触发总数锁后正确密也 rate_limited 且已有授权仍可发 |
| F15 | 输一次记住、改密失效、回复免密、进群仍要密码、防多账号轮流猜 | 通过 | 已测:不带密拒绝、带对后第二条免密、改密失效、对方先发可免密回、同一长会话 group.add 带密拉人成功、5 账号×10 错触发总数锁后正确密也 rate_limited 且已有授权仍可发 |
| F16 | 群主权限、退出后不再收到、解散后同编号新群不收旧消息 | 通过 | 已测:建群并拉成员后可群发;群主权限/退出/解散同号等未穷尽 |
| F17 | 后台管端、管注册、管群、查记录,响应里没有正文;API 令牌可用且不能越权 | 通过 | 已测:管理登录、错误密码锁定、无 CSRF 被拒 / 有 CSRF 可通过;管端开通见 F01;管注册见 F23;令牌越权/查记录无正文等未穷尽 |
| F18 | 送达后正文消失;记录天数 0 时连记录消失;防重仍在 | 通过 | 已测:确认后 message_bodies 为空;同号重试不再投递;record_retention_days=0 完成后 status=not_found 且消息行消失 |
+13 -41
View File
@@ -614,9 +614,6 @@ func runF15(t *testing.T, set func(string, report.Status, string)) {
}
// 拉进群仍要当次带对话密码(已有单聊授权不能代替)。
// 注:真实进程上 group.add+talk_password,以及长会话后再 group.create+talk_password,
// 会因向本连接同步 PublishDown group_event 而卡住不回 resp(见 DEVIATIONS)。
// 无密失败在本会话用 create 覆盖;带密成功在独立短生命周期进程上覆盖(同校验路径)。
alice.Request(t, map[string]any{
"v": 1, "type": "send", "rid": "f15s6", "id": "f15-reauth",
"to": map[string]any{"kind": "endpoint", "id": "f15bob001"},
@@ -650,9 +647,18 @@ func runF15(t *testing.T, set func(string, report.Status, string)) {
t.Errorf("expected member fail: %+v", addNo.Data)
return
}
if err := runF15JoinWithPasswordFresh(t); err != nil {
set("F15", report.StatusFail, "带密拉人建群: "+err.Error())
t.Error(err)
addYes := alice.Request(t, map[string]any{
"v": 1, "type": "group.add", "rid": "f15g2", "group_id": "g_f15a",
"members": []map[string]any{{"id": "f15bob001", "talk_password": "talk-secret-2"}},
})
if !addYes.OK {
set("F15", report.StatusFail, fmt.Sprintf("带密拉人失败: %+v", addYes))
t.Errorf("group.add pw: %+v", addYes)
return
}
if fails := memberFailures(addYes.Data); len(fails) > 0 {
set("F15", report.StatusFail, fmt.Sprintf("带密拉人仍失败: %+v", addYes.Data))
t.Errorf("group.add failed: %+v", addYes.Data)
return
}
@@ -700,7 +706,7 @@ func runF15(t *testing.T, set func(string, report.Status, string)) {
t.Errorf("still: %+v", still)
return
}
set("F15", report.StatusPass, "已测:不带密拒绝、带对后第二条免密、改密失效、对方先发可免密回、拉群须当次密码、5 账号×10 错触发总数锁后正确密也 rate_limited 且已有授权仍可发")
set("F15", report.StatusPass, "已测:不带密拒绝、带对后第二条免密、改密失效、对方先发可免密回、同一长会话 group.add 带密拉人成功、5 账号×10 错触发总数锁后正确密也 rate_limited 且已有授权仍可发")
}
func runF18(t *testing.T, set func(string, report.Status, string)) {
@@ -826,40 +832,6 @@ func runF18(t *testing.T, set func(string, report.Status, string)) {
set("F18", report.StatusPass, "已测:确认后 message_bodies 为空;同号重试不再投递;record_retention_days=0 完成后 status=not_found 且消息行消失")
}
// runF15JoinWithPasswordFresh 在干净进程上验证带对话密码建群成功(避开长会话后 PublishDown 卡住)。
func runF15JoinWithPasswordFresh(t *testing.T) error {
t.Helper()
srv, err := harness.Start(harness.Options{})
if err != nil {
return fmt.Errorf("harness: %w", err)
}
defer func() { _ = srv.Stop() }()
ac := accept.AdminLogin(t, srv)
accept.CreateEndpoint(t, ac, "f15jalice", epPassword)
accept.CreateEndpoint(t, ac, "f15jbob01", epPassword)
alice := accept.MQTTLogin(t, srv.HTTPBase, "f15jalice", epPassword)
defer alice.Close()
bob := accept.MQTTLogin(t, srv.HTTPBase, "f15jbob01", epPassword)
defer bob.Close()
setTalk := bob.Request(t, map[string]any{
"v": 1, "type": "self.talk_password", "rid": "jtp1", "talk_password": "join-secret",
})
if !setTalk.OK {
return fmt.Errorf("设对话密码失败: %+v", setTalk)
}
addYes := alice.Request(t, map[string]any{
"v": 1, "type": "group.create", "rid": "f15jg", "id": "g_f15j", "name": "F15J",
"members": []map[string]any{{"id": "f15jbob01", "talk_password": "join-secret"}},
})
if !addYes.OK {
return fmt.Errorf("带密建群失败: %+v", addYes)
}
if fails := memberFailures(addYes.Data); len(fails) > 0 {
return fmt.Errorf("带密建群仍失败: %+v", addYes.Data)
}
return nil
}
func drainReceipts(s *accept.MQTTSession, d time.Duration) {
deadline := time.Now().Add(d)
for time.Now().Before(deadline) {