feat: support batch message recall

This commit is contained in:
richjohnrambo
2026-09-15 10:46:07 +08:00
parent 9ec5da5b02
commit 4f6a996922
4 changed files with 201 additions and 4 deletions
+77
View File
@@ -7647,6 +7647,83 @@ func TestServeIMMessageRecall(t *testing.T) {
}
}
func TestServeIMMessageBatchRecallPartialSuccess(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
actor := types.Uid(42)
expectIMBearer(t, ctrl, "token-1", 7, actor)
oldSubs := store.Subs
oldMessages := store.Messages
subs := mock_store.NewMockSubsPersistenceInterface(ctrl)
messages := mock_store.NewMockMessagesPersistenceInterface(ctrl)
store.Subs = subs
store.Messages = messages
defer func() {
store.Subs = oldSubs
store.Messages = oldMessages
}()
sub := &types.Subscription{
TenantID: 7,
User: actor.String(),
Topic: "grpRecall",
ModeWant: types.ModeCFull,
ModeGiven: types.ModeCFull,
}
subs.EXPECT().Get(types.TenantID(7), "grpRecall", actor, false).Return(sub, nil).Times(2)
messages.EXPECT().GetOne(types.TenantID(7), "grpRecall", int64(9)).Return(&types.Message{
TenantID: 7,
SeqId: 9,
Topic: "grpRecall",
From: actor.String(),
Version: 1,
ObjHeader: types.ObjHeader{CreatedAt: time.Now().Add(-time.Second)},
}, nil)
messages.EXPECT().Recall(types.TenantID(7), "grpRecall", int64(9), actor, 1, gomock.Any()).Return(&types.Message{
TenantID: 7,
SeqId: 9,
Topic: "grpRecall",
From: actor.String(),
Version: 2,
RecalledAt: ptrTime(time.Now().UTC()),
RecalledBy: actor.String(),
ObjHeader: types.ObjHeader{UpdatedAt: time.Now().UTC()},
}, nil)
messages.EXPECT().GetOne(types.TenantID(7), "grpRecall", int64(10)).Return(&types.Message{
TenantID: 7,
SeqId: 10,
Topic: "grpRecall",
From: actor.String(),
Version: 2,
ObjHeader: types.ObjHeader{CreatedAt: time.Now().Add(-time.Second)},
}, nil)
messages.EXPECT().Recall(types.TenantID(7), "grpRecall", int64(10), actor, 1, gomock.Any()).Return(nil, types.ErrDuplicate)
req := httptest.NewRequest(http.MethodPost, "/v1/im/topics/grpRecall/messages/recall",
bytes.NewBufferString(`{"items":[{"seq":9},{"seq":10,"version":1}],"reason":"mistake"}`))
req.Header.Set("Authorization", "Bearer token-1")
rec := httptest.NewRecorder()
serveIMMessageBatchRecall(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status: got %d, want %d; body=%s", rec.Code, http.StatusOK, rec.Body.String())
}
data := decodeIMHTTPResponse(t, rec).Data.(map[string]any)
items := data["items"].([]any)
if len(items) != 2 {
t.Fatalf("items length: got %d, want 2", len(items))
}
first := items[0].(map[string]any)
if first["seq"].(float64) != 9 || first["status"] != "recalled" || first["version"].(float64) != 2 {
t.Fatalf("unexpected first item: %#v", first)
}
second := items[1].(map[string]any)
if second["seq"].(float64) != 10 || second["status"] != "failed" || second["reason"] != "VERSION_CONFLICT" {
t.Fatalf("unexpected second item: %#v", second)
}
}
func TestServeIMMessageRecallNormalizesP2PUserTopic(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()