198 lines
5.1 KiB
Go
198 lines
5.1 KiB
Go
// SPDX-FileCopyrightText: 2021 The NGI Pointer Secure-Scuttlebutt Team of 2020/2021
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package go_test
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/ssbc/go-muxrpc/v2"
|
|
refs "github.com/ssbc/go-ssb-refs"
|
|
"github.com/ssbc/go-ssb-room/v2/muxrpc/handlers/tunnel/server"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// this tests the new room.attendants call
|
|
// basically the same test as endpoints_test
|
|
func TestRoomAttendants(t *testing.T) {
|
|
testInit(t)
|
|
r := require.New(t)
|
|
a := assert.New(t)
|
|
|
|
testPath := filepath.Join("testrun", t.Name())
|
|
os.RemoveAll(testPath)
|
|
|
|
ctx := context.Background()
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
t.Cleanup(cancel)
|
|
|
|
// create the roomsrv
|
|
ts := makeNamedTestBot(t, "server", ctx, nil)
|
|
ctx = ts.ctx
|
|
|
|
// three new clients, connected to server automaticaly
|
|
alf := ts.makeTestClient("alf")
|
|
bre := ts.makeTestClient("bre")
|
|
carl := ts.makeTestClient("carl")
|
|
|
|
// start with carl
|
|
// ===============
|
|
carlsSource, err := carl.Source(ctx, muxrpc.TypeJSON, muxrpc.Method{"room", "attendants"})
|
|
r.NoError(err)
|
|
t.Log("carl opened attendants")
|
|
|
|
// first message should be initial state
|
|
a.True(carlsSource.Next(ctx))
|
|
var initState server.AttendantsInitialState
|
|
decodeJSONsrc(t, carlsSource, &initState)
|
|
a.Equal("state", initState.Type)
|
|
a.Len(initState.IDs, 1)
|
|
a.True(initState.IDs[0].Equal(carl.feed))
|
|
|
|
announcementsForCarl := make(announcements)
|
|
go logAttendantsStream(ts, carlsSource, "carl", announcementsForCarl)
|
|
time.Sleep(1 * time.Second) // give some time to process new events
|
|
|
|
a.Len(announcementsForCarl, 0, "none yet")
|
|
|
|
// let alf join the room
|
|
// =====================
|
|
alfsSource, err := alf.Source(ctx, muxrpc.TypeJSON, muxrpc.Method{"room", "attendants"})
|
|
r.NoError(err)
|
|
|
|
// first message should be initial state
|
|
a.True(alfsSource.Next(ctx))
|
|
decodeJSONsrc(t, alfsSource, &initState)
|
|
a.Equal("state", initState.Type)
|
|
a.Len(initState.IDs, 2)
|
|
assertListContains(t, initState.IDs, carl.feed)
|
|
assertListContains(t, initState.IDs, alf.feed)
|
|
|
|
announcementsForAlf := make(announcements)
|
|
go logAttendantsStream(ts, alfsSource, "alf", announcementsForAlf)
|
|
time.Sleep(1 * time.Second) // give some time to process new events
|
|
|
|
// assert what alf saw
|
|
var seen bool
|
|
a.Len(announcementsForAlf, 0, "none yet")
|
|
|
|
// assert what carl saw
|
|
_, seen = announcementsForCarl[alf.feed.String()]
|
|
a.True(seen, "carl saw alf")
|
|
|
|
// let bre join the room
|
|
bresSource, err := bre.Source(ctx, muxrpc.TypeJSON, muxrpc.Method{"room", "attendants"})
|
|
r.NoError(err)
|
|
|
|
// first message should be initial state
|
|
a.True(bresSource.Next(ctx))
|
|
decodeJSONsrc(t, bresSource, &initState)
|
|
a.Equal("state", initState.Type)
|
|
a.Len(initState.IDs, 3)
|
|
assertListContains(t, initState.IDs, alf.feed)
|
|
assertListContains(t, initState.IDs, bre.feed)
|
|
assertListContains(t, initState.IDs, carl.feed)
|
|
|
|
announcementsForBre := make(announcements)
|
|
go logAttendantsStream(ts, bresSource, "bre", announcementsForBre)
|
|
|
|
time.Sleep(1 * time.Second) // give some time to process new events
|
|
|
|
a.Len(announcementsForBre, 0, "none yet")
|
|
|
|
// the two present people saw her
|
|
_, seen = announcementsForAlf[bre.feed.String()]
|
|
a.True(seen, "alf saw bre")
|
|
|
|
_, seen = announcementsForCarl[bre.feed.String()]
|
|
a.True(seen, "carl saw alf")
|
|
|
|
// shutdown alf first
|
|
alf.Terminate()
|
|
|
|
time.Sleep(1 * time.Second) // give some time to process new events
|
|
|
|
// bre and arl should have removed him
|
|
|
|
_, seen = announcementsForBre[alf.feed.String()]
|
|
a.False(seen, "alf should be gone for bre")
|
|
|
|
_, seen = announcementsForCarl[alf.feed.String()]
|
|
a.False(seen, "alf should be gone for carl")
|
|
|
|
// terminate server and the clients
|
|
ts.srv.Shutdown()
|
|
bre.Terminate()
|
|
carl.Terminate()
|
|
ts.srv.Close()
|
|
|
|
// wait for all muxrpc serve()s to exit
|
|
r.NoError(ts.serveGroup.Wait())
|
|
cancel()
|
|
|
|
}
|
|
|
|
func assertListContains(t *testing.T, lst []refs.FeedRef, who refs.FeedRef) {
|
|
var found = false
|
|
for _, feed := range lst {
|
|
if feed.Equal(who) {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Errorf("did not find %s in list of %d", who.ShortSigil(), len(lst))
|
|
}
|
|
}
|
|
|
|
func decodeJSONsrc(t *testing.T, src *muxrpc.ByteSource, val interface{}) {
|
|
err := src.Reader(func(rd io.Reader) error {
|
|
return json.NewDecoder(rd).Decode(val)
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// consume endpoint messaes and put each peer on the passed map
|
|
func logAttendantsStream(ts *testSession, src *muxrpc.ByteSource, who string, a announcements) {
|
|
var update server.AttendantsUpdate
|
|
|
|
for src.Next(ts.ctx) {
|
|
body, err := src.Bytes()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
// ts.t.Log(who, "got body:", string(body))
|
|
|
|
err = json.Unmarshal(body, &update)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
ts.t.Log(who, "got an update:", update.Type, update.ID.ShortSigil())
|
|
|
|
switch update.Type {
|
|
case "joined":
|
|
a[update.ID.String()] = struct{}{}
|
|
case "left":
|
|
delete(a, update.ID.String())
|
|
default:
|
|
ts.t.Fatalf("%s: unexpected update type: %v", who, update.Type)
|
|
}
|
|
}
|
|
|
|
if err := src.Err(); err != nil {
|
|
ts.t.Log(who, "source errored: ", err)
|
|
return
|
|
}
|
|
|
|
ts.t.Log(who, "stream closed")
|
|
}
|