mirror of
https://github.com/mautrix/whatsapp.git
synced 2026-08-24 13:04:56 -04:00
229 lines
7.6 KiB
Go
229 lines
7.6 KiB
Go
package voip
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"maunium.net/go/mautrix/event"
|
|
"maunium.net/go/mautrix/id"
|
|
)
|
|
|
|
func TestSupportedMatrixRTCEventTypesHaveExplicitClasses(t *testing.T) {
|
|
types := SupportedMatrixRTCEventTypes()
|
|
if len(types) != 10 {
|
|
t.Fatalf("SupportedMatrixRTCEventTypes returned %d types, want 10", len(types))
|
|
}
|
|
for _, evtType := range types {
|
|
switch evtType.Type {
|
|
case EventTypeGroupCall, EventTypeGroupCallMember:
|
|
if evtType.Class != event.StateEventType {
|
|
t.Fatalf("%s class = %v, want state", evtType.Type, evtType.Class)
|
|
}
|
|
case EventTypeRTCMembership:
|
|
if evtType.Class != event.StateEventType && evtType.Class != event.MessageEventType {
|
|
t.Fatalf("%s class = %v, want state or message", evtType.Type, evtType.Class)
|
|
}
|
|
case EventTypeRTCNotification, EventTypeCallNotify, EventTypeRTCDecline,
|
|
EventTypeElementCallReaction, event.EventReaction.Type, event.EventRedaction.Type:
|
|
if evtType.Class != event.MessageEventType {
|
|
t.Fatalf("%s class = %v, want message", evtType.Type, evtType.Class)
|
|
}
|
|
default:
|
|
t.Fatalf("unexpected MatrixRTC event type %s", evtType.Type)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseElementCallReactionEvent(t *testing.T) {
|
|
evt := &event.Event{
|
|
ID: id.EventID("$reaction"),
|
|
Type: ElementCallReactionEventType(),
|
|
RoomID: id.RoomID("!room:example.com"),
|
|
Sender: id.UserID("@alice:example.com"),
|
|
Content: event.Content{Raw: map[string]any{
|
|
"m.relates_to": map[string]any{
|
|
"rel_type": "m.reference",
|
|
"event_id": "$membership",
|
|
},
|
|
"emoji": "❤️",
|
|
"name": "generic",
|
|
}},
|
|
}
|
|
parsed, ok := ParseMatrixRTCEvent(evt)
|
|
if !ok {
|
|
t.Fatal("ParseMatrixRTCEvent did not recognize Element Call reaction")
|
|
}
|
|
if parsed.Kind != MatrixRTCEventKindCallReaction ||
|
|
parsed.EventID != "$reaction" ||
|
|
parsed.RelatesToEventID != "$membership" ||
|
|
parsed.ReactionEmoji != "❤️" {
|
|
t.Fatalf("unexpected parsed reaction: %+v", parsed)
|
|
}
|
|
}
|
|
|
|
func TestSupportedWhatsAppCallReactions(t *testing.T) {
|
|
for _, emoji := range []string{"👍", "❤️", "😂", "😮", "😢", "🙏"} {
|
|
normalized, ok := NormalizeWhatsAppCallReaction(emoji)
|
|
if !ok || normalized != emoji {
|
|
t.Fatalf("NormalizeWhatsAppCallReaction(%q) = %q, %t", emoji, normalized, ok)
|
|
}
|
|
}
|
|
if normalized, ok := NormalizeWhatsAppCallReaction("🎉"); ok || normalized != "" {
|
|
t.Fatalf("unsupported reaction normalized to %q, %t", normalized, ok)
|
|
}
|
|
}
|
|
|
|
func TestParseMatrixRTCDeclineEvent(t *testing.T) {
|
|
evt := &event.Event{
|
|
Type: event.Type{Type: EventTypeRTCDecline, Class: event.MessageEventType},
|
|
RoomID: id.RoomID("!room:example.com"),
|
|
Sender: id.UserID("@alice:example.com"),
|
|
Content: event.Content{Raw: map[string]any{
|
|
"call_id": "call-1",
|
|
"device_id": "DEVICE",
|
|
"session_id": "SESSION",
|
|
}},
|
|
}
|
|
parsed, ok := ParseMatrixRTCEvent(evt)
|
|
if !ok {
|
|
t.Fatalf("ParseMatrixRTCEvent did not recognize decline event")
|
|
}
|
|
if parsed.Kind != MatrixRTCEventKindRTCDecline {
|
|
t.Fatalf("kind = %q, want %q", parsed.Kind, MatrixRTCEventKindRTCDecline)
|
|
}
|
|
if parsed.CallID != "call-1" || parsed.DeviceID != "DEVICE" || parsed.SessionID != "SESSION" {
|
|
t.Fatalf("unexpected parsed event: %+v", parsed)
|
|
}
|
|
}
|
|
|
|
func TestParseMatrixRTCMembershipEvent(t *testing.T) {
|
|
stateKey := "@alice:example.com"
|
|
evt := &event.Event{
|
|
Type: event.Type{Type: EventTypeRTCMembership, Class: event.StateEventType},
|
|
RoomID: id.RoomID("!room:example.com"),
|
|
Sender: id.UserID("@alice:example.com"),
|
|
StateKey: &stateKey,
|
|
Content: event.Content{Raw: map[string]any{
|
|
"memberships": []any{map[string]any{
|
|
"call_id": "call-2",
|
|
"device_id": "DEVICE",
|
|
"session_id": "SESSION",
|
|
"lifetime_ms": float64(60000),
|
|
"foci_preferred": []any{map[string]any{
|
|
"type": "livekit",
|
|
"livekit_service_url": "https://rtc.example.com/jwt",
|
|
}},
|
|
}},
|
|
}},
|
|
}
|
|
parsed, ok := ParseMatrixRTCEvent(evt)
|
|
if !ok {
|
|
t.Fatalf("ParseMatrixRTCEvent did not recognize membership event")
|
|
}
|
|
if parsed.Kind != MatrixRTCEventKindRTCMembership || parsed.StateKey != stateKey {
|
|
t.Fatalf("unexpected parsed event metadata: %+v", parsed)
|
|
}
|
|
if parsed.CallID != "call-2" || parsed.DeviceID != "DEVICE" || parsed.SessionID != "SESSION" {
|
|
t.Fatalf("unexpected parsed event identifiers: %+v", parsed)
|
|
}
|
|
if parsed.LifetimeMS != 60000 {
|
|
t.Fatalf("LifetimeMS = %d, want 60000", parsed.LifetimeMS)
|
|
}
|
|
if len(parsed.FociPreferred) != 1 || parsed.FociPreferred[0].LiveKitServiceURL != "https://rtc.example.com/jwt" {
|
|
t.Fatalf("unexpected foci: %+v", parsed.FociPreferred)
|
|
}
|
|
}
|
|
|
|
func TestBuildRTCMembershipContent(t *testing.T) {
|
|
session := MatrixRTCSession{
|
|
UserID: "@wa_123:example.com",
|
|
DeviceID: "WADEVICE",
|
|
Focus: Focus{
|
|
Type: "livekit",
|
|
LiveKitServiceURL: "https://rtc.example.com/jwt",
|
|
},
|
|
}
|
|
content := BuildRTCMembershipContent(session)
|
|
if content["slot_id"] != MatrixRTCDefaultSlotID {
|
|
t.Fatalf("slot_id = %q, want %q", content["slot_id"], MatrixRTCDefaultSlotID)
|
|
}
|
|
member := content["member"].(map[string]any)
|
|
if member["user_id"] != "@wa_123:example.com" || member["device_id"] != "WADEVICE" {
|
|
t.Fatalf("unexpected member: %+v", member)
|
|
}
|
|
transports := content["rtc_transports"].([]map[string]any)
|
|
if len(transports) != 1 || transports[0]["livekit_service_url"] != "https://rtc.example.com/jwt" {
|
|
t.Fatalf("unexpected transports: %+v", transports)
|
|
}
|
|
}
|
|
|
|
func TestParseBuiltRTCMembershipContent(t *testing.T) {
|
|
content := BuildRTCMembershipContent(MatrixRTCSession{
|
|
UserID: "@wa_123:example.com",
|
|
DeviceID: "WADEVICE",
|
|
Intent: "audio",
|
|
Focus: Focus{
|
|
Type: "livekit",
|
|
LiveKitServiceURL: "https://rtc.example.com/jwt",
|
|
},
|
|
})
|
|
evt := &event.Event{
|
|
Type: RTCMembershipEventType(event.MessageEventType),
|
|
RoomID: id.RoomID("!room:example.com"),
|
|
Sender: id.UserID("@wa_123:example.com"),
|
|
Content: event.Content{Raw: content},
|
|
}
|
|
parsed, ok := ParseMatrixRTCEvent(evt)
|
|
if !ok {
|
|
t.Fatalf("ParseMatrixRTCEvent did not recognize membership event")
|
|
}
|
|
if parsed.Intent != "audio" {
|
|
t.Fatalf("Intent = %q, want audio", parsed.Intent)
|
|
}
|
|
if len(parsed.FociPreferred) != 1 || parsed.FociPreferred[0].LiveKitServiceURL != "https://rtc.example.com/jwt" {
|
|
t.Fatalf("unexpected foci: %+v", parsed.FociPreferred)
|
|
}
|
|
if !MatrixRTCEventHasJoinContent(parsed) {
|
|
t.Fatalf("MatrixRTCEventHasJoinContent returned false for a built membership")
|
|
}
|
|
}
|
|
|
|
func TestMatrixRTCEventHasJoinContentRejectsStickyCleanup(t *testing.T) {
|
|
evt := MatrixRTCEvent{
|
|
Kind: MatrixRTCEventKindRTCMembership,
|
|
Raw: EmptyMatrixRTCContent("sticky"),
|
|
}
|
|
if MatrixRTCEventHasJoinContent(evt) {
|
|
t.Fatalf("MatrixRTCEventHasJoinContent returned true for sticky cleanup content")
|
|
}
|
|
}
|
|
|
|
func TestMatrixRTCEventHasJoinContentRejectsMetadataWithoutFocus(t *testing.T) {
|
|
for _, raw := range []map[string]any{
|
|
{
|
|
"application": map[string]any{"type": MatrixRTCApplicationCall},
|
|
},
|
|
{
|
|
"slot_id": MatrixRTCDefaultSlotID,
|
|
"application": map[string]any{"type": MatrixRTCApplicationCall},
|
|
"member": map[string]any{"user_id": "@alice:example.com", "device_id": "DEVICE"},
|
|
},
|
|
} {
|
|
evt := MatrixRTCEvent{Kind: MatrixRTCEventKindRTCMembership, Raw: raw}
|
|
if MatrixRTCEventHasJoinContent(evt) {
|
|
t.Fatalf("MatrixRTCEventHasJoinContent returned true for metadata-only content: %+v", raw)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBuildRTCNotificationContentCapsLifetime(t *testing.T) {
|
|
content := BuildRTCNotificationContent(testTime, 5*time.Minute, "audio")
|
|
if content["notification_type"] != "ring" {
|
|
t.Fatalf("notification_type = %q, want ring", content["notification_type"])
|
|
}
|
|
if content["lifetime"] != int64(90000) {
|
|
t.Fatalf("lifetime = %v, want 90000", content["lifetime"])
|
|
}
|
|
}
|
|
|
|
var testTime = time.Unix(123, 0)
|