* 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>
382 lines
8.4 KiB
Go
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")
|
|
})
|
|
}
|