Files
protocol/livekit/types_test.go
Nishad 08846e86a9 List phone number updates (#1323)
* Updates to the list phone number api
1. Adding new status for phone number called offline
2. Adding offline count in list phone number response
3. Adding dispatch rules ids as a property for phone number so we can return it via the api instead of a single dispatch rule id

* generated protobuf

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-12-01 21:11:53 -08:00

382 lines
8.4 KiB
Go

package livekit
import (
"context"
"encoding/base64"
"fmt"
"slices"
"testing"
"github.com/dennwc/iters"
"github.com/stretchr/testify/require"
proto "google.golang.org/protobuf/proto"
"gopkg.in/yaml.v3"
)
func TestUnmarshallRoomConfiguration(t *testing.T) {
y := `
a:
name: room_name
egress:
room:
room_name: room_name
agents:
- {}
- agent_name: ag
metadata: mm
min_playout_delay: 42
`
obj := make(map[string]*RoomConfiguration)
err := yaml.Unmarshal([]byte(y), &obj)
require.NoError(t, err)
require.Equal(t, 1, len(obj))
re := obj["a"]
require.NotNil(t, re)
require.Equal(t, re.Name, "room_name")
require.Equal(t, re.MinPlayoutDelay, uint32(42))
require.Equal(t, re.Egress.Room.RoomName, "room_name")
require.Equal(t, 2, len(re.Agents))
require.Equal(t, "ag", re.Agents[1].AgentName)
require.Equal(t, "mm", re.Agents[1].Metadata)
}
func TestMarshallRoomConfiguration(t *testing.T) {
r := &RoomConfiguration{
Name: "name",
MaxParticipants: 42,
EmptyTimeout: 12,
DepartureTimeout: 13,
MinPlayoutDelay: 14,
MaxPlayoutDelay: 15,
Egress: &RoomEgress{
Room: &RoomCompositeEgressRequest{
AudioOnly: true,
RoomName: "room name",
},
},
Agents: []*RoomAgentDispatch{
{
AgentName: "agent name",
},
},
}
b, err := yaml.Marshal(r)
require.NoError(t, err)
var ur RoomConfiguration
err = yaml.Unmarshal(b, &ur)
require.NoError(t, err)
require.True(t, proto.Equal(r, &ur))
}
func TestUnmarshallRoomEgress(t *testing.T) {
y := `
a:
room:
room_name: room name
b:
participant:
file_outputs:
- s3:
access_key: key
`
obj := make(map[string]*RoomEgress)
err := yaml.Unmarshal([]byte(y), &obj)
require.NoError(t, err)
require.Equal(t, 2, len(obj))
re := obj["a"]
require.NotNil(t, re)
require.Equal(t, re.Room.RoomName, "room name")
re = obj["b"]
require.NotNil(t, re)
require.Equal(t, 1, len(re.Participant.FileOutputs))
require.Equal(t, "key", re.Participant.FileOutputs[0].Output.(*EncodedFileOutput_S3).S3.AccessKey)
}
func TestMarshallRoomEgress(t *testing.T) {
e := &RoomEgress{
Room: &RoomCompositeEgressRequest{
AudioOnly: true,
RoomName: "room name",
},
}
b, err := yaml.Marshal(e)
require.NoError(t, err)
var ue RoomEgress
err = yaml.Unmarshal(b, &ue)
require.NoError(t, err)
require.True(t, proto.Equal(e, &ue))
}
func TestUnmarshallRoomAgent(t *testing.T) {
y := `
a:
dispatches:
- {}
- agent_name: ag
metadata: mm
`
obj := make(map[string]*RoomAgent)
err := yaml.Unmarshal([]byte(y), &obj)
require.NoError(t, err)
require.Equal(t, 1, len(obj))
re := obj["a"]
require.NotNil(t, re)
require.Equal(t, len(re.Dispatches), 2)
require.Equal(t, "ag", re.Dispatches[1].AgentName)
require.Equal(t, "mm", re.Dispatches[1].Metadata)
}
func TestMarshallRoomAgent(t *testing.T) {
a := &RoomAgent{
Dispatches: []*RoomAgentDispatch{
&RoomAgentDispatch{
AgentName: "agent name",
},
},
}
b, err := yaml.Marshal(a)
require.NoError(t, err)
var ua RoomAgent
err = yaml.Unmarshal(b, &ua)
require.NoError(t, err)
require.True(t, proto.Equal(a, &ua))
}
var _ PageItem = testPageItem("")
type testPageItem string
func (t testPageItem) ID() string {
return string(t)
}
type testPageReq struct {
Page *Pagination
ReturnEmpty bool
}
func (t *testPageReq) GetPage() *Pagination {
return t.Page
}
func (t *testPageReq) Filter(v testPageItem) bool {
return true
}
type testPageResp []testPageItem
func (t testPageResp) GetItems() []testPageItem {
return t
}
func TestListPageIter(t *testing.T) {
const page = 3
var (
all []testPageItem
)
for i := 0; i < 10; i++ {
all = append(all, testPageItem(fmt.Sprintf("%03d", i)))
}
pageFunc := func(ctx context.Context, req *testPageReq) (testPageResp, error) {
limit := -1
if req.Page != nil {
limit = int(req.Page.Limit)
if limit == 0 {
limit = page
}
}
if req.ReturnEmpty {
return make(testPageResp, page), nil
}
var out testPageResp
for _, v := range all {
if req.Filter(v) && req.Page.Filter(v) {
out = append(out, v)
if limit > 0 && len(out) >= limit {
break
}
}
}
return out, nil
}
exp := all
testList := func(t testing.TB, req *testPageReq) {
it := ListPageIter(pageFunc, req)
got, err := iters.AllPages(context.Background(), it)
require.NoError(t, err)
require.Equal(t, exp, got)
}
t.Run("legacy", func(t *testing.T) {
testList(t, &testPageReq{})
})
t.Run("pagination", func(t *testing.T) {
testList(t, &testPageReq{Page: &Pagination{}})
})
t.Run("limit", func(t *testing.T) {
testList(t, &testPageReq{Page: &Pagination{Limit: 5}})
})
t.Run("no ids", func(t *testing.T) {
it := ListPageIter(pageFunc, &testPageReq{Page: &Pagination{}, ReturnEmpty: true})
got, err := iters.AllPages(context.Background(), it)
require.NoError(t, err)
require.Equal(t, []testPageItem(nil), got)
})
}
func TestListUpdate(t *testing.T) {
var cases = []struct {
Name string
Arr []string
Update *ListUpdate
Exp []string
Err bool
}{
{
Name: "empty update",
Update: &ListUpdate{},
Err: true,
},
{
Name: "clear and set",
Update: &ListUpdate{Clear: true, Set: []string{"a"}},
Err: true,
},
{
Name: "clear and add",
Update: &ListUpdate{Clear: true, Add: []string{"a"}},
Err: true,
},
{
Name: "set and add",
Update: &ListUpdate{Set: []string{"a"}, Add: []string{"b"}},
Err: true,
},
{
Name: "set and remove",
Update: &ListUpdate{Set: []string{"a"}, Remove: []string{"b"}},
Err: true,
},
{
Name: "clear",
Arr: []string{"a", "b"},
Update: &ListUpdate{Clear: true},
Exp: nil,
},
{
Name: "set",
Arr: []string{"a"},
Update: &ListUpdate{Set: []string{"b"}},
Exp: []string{"b"},
},
{
Name: "add",
Arr: []string{"a", "b"},
Update: &ListUpdate{Add: []string{"b", "c"}},
Exp: []string{"a", "b", "c"},
},
{
Name: "remove",
Arr: []string{"a", "b"},
Update: &ListUpdate{Remove: []string{"b", "c"}},
Exp: []string{"a"},
},
{
Name: "add and remove",
Arr: []string{"a", "b", "c"},
Update: &ListUpdate{Add: []string{"b", "d"}, Remove: []string{"c", "e"}},
Exp: []string{"a", "b", "d"},
},
}
for _, c := range cases {
t.Run(c.Name, func(t *testing.T) {
prev := slices.Clone(c.Arr)
out, err := c.Update.Apply(c.Arr)
if c.Err {
require.Error(t, err)
return
}
require.NoError(t, err)
require.Equal(t, c.Exp, out)
require.Equal(t, prev, c.Arr)
})
}
}
func TestEncodeTokenPagination(t *testing.T) {
t.Run("encode and decode", func(t *testing.T) {
offset := int32(10)
limit := int32(50)
tokenPagination, err := EncodeTokenPagination(offset, limit)
require.NoError(t, err)
require.NotNil(t, tokenPagination)
require.NotEmpty(t, tokenPagination.Token)
decodedOffset, decodedLimit, err := DecodeTokenPagination(tokenPagination)
require.NoError(t, err)
require.Equal(t, offset, decodedOffset)
require.Equal(t, limit, decodedLimit)
})
t.Run("encode zero values", func(t *testing.T) {
tokenPagination, err := EncodeTokenPagination(0, 0)
require.NoError(t, err)
require.NotNil(t, tokenPagination)
require.NotEmpty(t, tokenPagination.Token)
decodedOffset, decodedLimit, err := DecodeTokenPagination(tokenPagination)
require.NoError(t, err)
require.Equal(t, int32(0), decodedOffset)
require.Equal(t, int32(0), decodedLimit)
})
t.Run("decode nil token pagination", func(t *testing.T) {
offset, limit, err := DecodeTokenPagination(nil)
require.NoError(t, err)
require.Equal(t, int32(0), offset)
require.Equal(t, int32(0), limit)
})
t.Run("decode empty token", func(t *testing.T) {
tp := &TokenPagination{Token: ""}
offset, limit, err := DecodeTokenPagination(tp)
require.NoError(t, err)
require.Equal(t, int32(0), offset)
require.Equal(t, int32(0), limit)
})
t.Run("decode invalid token", func(t *testing.T) {
tp := &TokenPagination{Token: "invalid-token"}
_, _, err := DecodeTokenPagination(tp)
require.Error(t, err)
require.Contains(t, err.Error(), "failed to decode token")
})
t.Run("decode invalid json", func(t *testing.T) {
invalidJSON := base64.URLEncoding.EncodeToString([]byte("not json"))
tp := &TokenPagination{Token: invalidJSON}
_, _, err := DecodeTokenPagination(tp)
require.Error(t, err)
require.Contains(t, err.Error(), "failed to unmarshal")
})
}