2026-05-20 14:34:10 +08:00

154 lines
4.4 KiB
Go

package roomnotice
import (
"context"
"encoding/json"
"errors"
"testing"
"time"
roomeventsv1 "hyapp.local/api/proto/events/room/v1"
"hyapp/pkg/tencentim"
)
func TestProcessRoomKickNoticesPublishesPrivateIM(t *testing.T) {
repo := &fakeRepository{
events: []RoomKickEvent{{
AppCode: "lalu",
EventID: "evt-room-kick-1",
EventType: "RoomUserKicked",
RoomID: "room_10001",
RoomVersion: 18,
ActorUserID: 10001,
TargetUserID: 20001,
OccurredAtMS: 1710000000123,
CreatedAtMS: 1710000000124,
}},
}
publisher := &fakePublisher{}
service := New(Config{NodeID: "notice-test"}, repo, publisher)
processed, err := service.ProcessRoomKickNotices(context.Background(), RoomNoticeWorkerOptions{
WorkerID: "room-notice-test",
BatchSize: 10,
LockTTL: time.Second,
PublishTimeout: time.Second,
MaxRetryCount: 3,
InitialBackoff: time.Second,
MaxBackoff: time.Second,
})
if err != nil {
t.Fatalf("ProcessRoomKickNotices failed: %v", err)
}
if processed != 1 {
t.Fatalf("processed=%d, want 1", processed)
}
if len(publisher.messages) != 1 {
t.Fatalf("published messages=%d, want 1", len(publisher.messages))
}
message := publisher.messages[0]
if message.ToAccount != "20001" || message.EventID != "evt-room-kick-1" || message.Ext != "room_notice" || message.Desc != "room_user_kicked" {
t.Fatalf("unexpected message: %+v", message)
}
if repo.deliveredEventID != "evt-room-kick-1" {
t.Fatalf("delivered event id=%q", repo.deliveredEventID)
}
var payload map[string]any
if err := json.Unmarshal(message.PayloadJSON, &payload); err != nil {
t.Fatalf("decode payload: %v", err)
}
if payload["event_type"] != "room_user_kicked" || payload["room_id"] != "room_10001" {
t.Fatalf("unexpected payload: %+v", payload)
}
if payload["target_user_id"].(float64) != 20001 || payload["actor_user_id"].(float64) != 10001 {
t.Fatalf("unexpected user payload: %+v", payload)
}
}
func TestProcessRoomKickNoticesMarksRetryableOnPublishError(t *testing.T) {
repo := &fakeRepository{
events: []RoomKickEvent{{
AppCode: "lalu",
EventID: "evt-room-kick-2",
EventType: "RoomUserKicked",
RoomID: "room_10001",
ActorUserID: 10001,
TargetUserID: 20001,
RetryCount: 1,
}},
}
service := New(Config{NodeID: "notice-test"}, repo, &fakePublisher{err: errors.New("im timeout")})
processed, err := service.ProcessRoomKickNotices(context.Background(), RoomNoticeWorkerOptions{
WorkerID: "room-notice-test",
BatchSize: 10,
LockTTL: time.Second,
PublishTimeout: time.Second,
MaxRetryCount: 3,
InitialBackoff: time.Second,
MaxBackoff: time.Second,
})
if err != nil {
t.Fatalf("ProcessRoomKickNotices failed: %v", err)
}
if processed != 1 {
t.Fatalf("processed=%d, want 1", processed)
}
if repo.retryEventID != "evt-room-kick-2" || repo.retryCount != 2 {
t.Fatalf("retry marker event=%q count=%d", repo.retryEventID, repo.retryCount)
}
if repo.failedEventID != "" {
t.Fatalf("event should be retryable, got failed=%q", repo.failedEventID)
}
}
type fakeRepository struct {
events []RoomKickEvent
deliveredEventID string
retryEventID string
failedEventID string
retryCount int
}
func (r *fakeRepository) ClaimRoomKickEvents(context.Context, string, int, time.Duration) ([]RoomKickEvent, error) {
return r.events, nil
}
func (r *fakeRepository) ClaimRoomKickEnvelope(context.Context, string, *roomeventsv1.EventEnvelope, time.Duration) (RoomKickEvent, bool, error) {
if len(r.events) == 0 {
return RoomKickEvent{}, false, nil
}
return r.events[0], true, nil
}
func (r *fakeRepository) MarkRoomKickDelivered(_ context.Context, event RoomKickEvent, _ []byte, _ int64) error {
r.deliveredEventID = event.EventID
return nil
}
func (r *fakeRepository) MarkRoomKickRetryable(_ context.Context, event RoomKickEvent, retryCount int, _ int64, _ string, _ int64) error {
r.retryEventID = event.EventID
r.retryCount = retryCount
return nil
}
func (r *fakeRepository) MarkRoomKickFailed(_ context.Context, event RoomKickEvent, retryCount int, _ string, _ int64) error {
r.failedEventID = event.EventID
r.retryCount = retryCount
return nil
}
type fakePublisher struct {
messages []tencentim.CustomUserMessage
err error
}
func (p *fakePublisher) PublishUserCustomMessage(_ context.Context, message tencentim.CustomUserMessage) error {
if p.err != nil {
return p.err
}
p.messages = append(p.messages, message)
return nil
}