2026-06-03 18:19:50 +08:00

132 lines
4.3 KiB
Go

package integration
import (
"bytes"
"context"
"io"
"net/http"
"testing"
"time"
roomeventsv1 "hyapp.local/api/proto/events/room/v1"
"hyapp/pkg/tencentim"
"hyapp/services/room-service/internal/room/outbox"
)
func TestRoomEventFromEnvelopeSkipsNonIMEvents(t *testing.T) {
record, err := outbox.Build("room-noop", "RoomCreated", 1, time.Now(), &roomeventsv1.RoomCreated{
OwnerUserId: 1,
SeatCount: 4,
Mode: "social",
})
if err != nil {
t.Fatalf("Build RoomCreated envelope failed: %v", err)
}
event, publish, err := roomEventFromEnvelope(record.Envelope)
if err != nil {
t.Fatalf("RoomCreated should be a no-op success: %v", err)
}
if publish {
t.Fatalf("RoomCreated must not publish Tencent IM message: %+v", event)
}
}
func TestRoomUserJoinedCarriesEntryVehicleSnapshot(t *testing.T) {
record, err := outbox.Build("room-vehicle", "RoomUserJoined", 9, time.Now(), &roomeventsv1.RoomUserJoined{
UserId: 42,
Role: "audience",
VisibleRegionId: 86,
EntryVehicle: &roomeventsv1.RoomEntryVehicleSnapshot{
ResourceId: 7001,
ResourceCode: "vehicle_gold",
Name: "Gold Vehicle",
AssetUrl: "https://cdn.example.com/vehicle.png",
PreviewUrl: "https://cdn.example.com/vehicle-preview.png",
AnimationUrl: "https://cdn.example.com/vehicle.svga",
MetadataJson: `{"speed":"fast"}`,
EntitlementId: "ent-vehicle",
ExpiresAtMs: 1999999999999,
},
})
if err != nil {
t.Fatalf("Build RoomUserJoined envelope failed: %v", err)
}
event, publish, err := roomEventFromEnvelope(record.Envelope)
if err != nil {
t.Fatalf("RoomUserJoined should decode: %v", err)
}
if !publish {
t.Fatal("RoomUserJoined must publish Tencent IM message")
}
if event.EntryVehicle == nil || event.EntryVehicle.ResourceID != 7001 || event.EntryVehicle.AnimationURL != "https://cdn.example.com/vehicle.svga" {
t.Fatalf("entry vehicle snapshot mismatch: %+v", event.EntryVehicle)
}
}
func TestRoomBackgroundChangedPublishesDedicatedIMEvent(t *testing.T) {
record, err := outbox.Build("room-bg", "RoomBackgroundChanged", 7, time.Now(), &roomeventsv1.RoomBackgroundChanged{
ActorUserId: 42,
BackgroundId: 101,
RoomBackgroundUrl: "https://cdn.example.com/bg.png",
})
if err != nil {
t.Fatalf("Build RoomBackgroundChanged envelope failed: %v", err)
}
event, publish, err := roomEventFromEnvelope(record.Envelope)
if err != nil {
t.Fatalf("RoomBackgroundChanged should decode: %v", err)
}
if !publish {
t.Fatal("RoomBackgroundChanged must publish Tencent IM message")
}
if event.EventType != "room_background_changed" || event.Attributes["room_background_url"] != "https://cdn.example.com/bg.png" || event.Attributes["background_id"] != "101" {
t.Fatalf("background IM event mismatch: %+v", event)
}
}
func TestTencentIMPublisherRemovesGroupMemberBeforeKickMessage(t *testing.T) {
paths := make([]string, 0, 2)
client, err := tencentim.NewRESTClient(tencentim.RESTConfig{
SDKAppID: 1400000000,
SecretKey: "secret",
AdminIdentifier: "administrator",
AdminUserSigTTL: time.Hour,
HTTPClient: &http.Client{Transport: roundTripFunc(func(request *http.Request) (*http.Response, error) {
paths = append(paths, request.URL.Path)
return &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(bytes.NewReader([]byte(`{"ActionStatus":"OK","ErrorCode":0,"ErrorInfo":""}`))),
Header: make(http.Header),
}, nil
})},
})
if err != nil {
t.Fatalf("NewRESTClient failed: %v", err)
}
record, err := outbox.Build("room-kick", "RoomUserKicked", 3, time.Now(), &roomeventsv1.RoomUserKicked{
ActorUserId: 1,
TargetUserId: 2,
})
if err != nil {
t.Fatalf("Build RoomUserKicked envelope failed: %v", err)
}
publisher := NewTencentIMPublisher(client)
if err := publisher.PublishOutboxEvent(context.Background(), record.Envelope); err != nil {
t.Fatalf("PublishOutboxEvent failed: %v", err)
}
if len(paths) != 2 || paths[0] != "/v4/group_open_http_svc/delete_group_member" || paths[1] != "/v4/group_open_http_svc/send_group_msg" {
t.Fatalf("kick outbox should delete member before system message, paths=%+v", paths)
}
}
type roundTripFunc func(*http.Request) (*http.Response, error)
func (f roundTripFunc) RoundTrip(request *http.Request) (*http.Response, error) {
return f(request)
}