Multi-Room Chat (#4)

* # This is a combination of 4 commits.
# This is the 1st commit message:

Chatroom example

# This is the commit message #2:

Avatar styling

# This is the commit message #3:

Styling

# This is the commit message #4:

cleanup

* Chatroom example

Avatar styling

Benchmark tests

Cleanup

ignore

Files

Cleanroom chatroom impl

* Rewrite.

* changes

* Fix Deadlocks. Start the rooms. Fix styling. Random things. Bookmarklet.

* Subset data

* Rm file

* Simplify User. Just Comparable.

* Remove method.
This commit is contained in:
Jeff Winkler
2025-11-11 18:30:40 -05:00
committed by GitHub
parent 5e9740813b
commit 779718a088
7 changed files with 637 additions and 9 deletions

View File

@@ -0,0 +1,100 @@
package main
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
type Statement struct {
text string
author TestUserInfo
}
type RoomData struct {
convo []Statement
}
type TestUserInfo struct {
Name string
}
func TestRoomsZero(t *testing.T) {
rooms := NewRooms[RoomData, TestUserInfo]()
assert.NotNil(t, rooms)
}
func TestRoomsMany(t *testing.T) {
names := []string{"a", "b"}
rooms := NewRooms[RoomData, TestUserInfo](names...)
assert.NotNil(t, rooms)
assert.Equal(t, 2, len(rooms.names))
// Visit
seen := 0
rooms.Visit(func(name string) { seen++ })
assert.Equal(t, seen, 2)
// GetRoom fail
_, ok := rooms.Get("z")
assert.False(t, ok)
// GetRoom
rm, ok := rooms.Get("a")
assert.True(t, ok)
assert.NotNil(t, rm)
assert.Equal(t, string("a"), rm.Name)
}
type DummySyncable struct {
room *Room[RoomData, TestUserInfo]
timesCalled int
}
func (ds *DummySyncable) Sync() {
// Data() hits deadlock conditions from Publish()
ds.room.GetData()
ds.timesCalled++
}
func TestRoomJoinLeaveChannels(t *testing.T) {
rooms := NewRooms[RoomData, TestUserInfo](string("a"))
rm, _ := rooms.Get("a")
u1 := TestUserInfo{"Bob"}
u1Context := DummySyncable{room: rm}
rooms.Start()
defer rooms.Stop()
uas := UserAndSync[RoomData, TestUserInfo]{user: &u1, sync: &u1Context}
// Joining a room does *not* mark it dirty. It's on the user to call Sync() -
// so the user gets the update immediately.
rm.Join(&uas)
// // Give it time to process
time.Sleep(1 * time.Millisecond)
assert.Equal(t, rm.dirty, false)
assert.Equal(t, rm.MemberCount(), 1)
// Room Data
rm.UpdateData(func(data *RoomData) {
data.convo = append(data.convo, Statement{"Hello", u1})
})
assert.Equal(t, rm.dirty, true)
data := rm.GetData()
assert.Equal(t, len(data.convo), 1)
// BROADCAST to connected users. Clears the dirty flag.
rm.Publish()
time.Sleep(1 * time.Millisecond)
assert.Equal(t, rm.dirty, false)
assert.Equal(t, u1Context.timesCalled, 1)
// Leave
rm.Leave(&u1)
time.Sleep(1 * time.Millisecond)
assert.Equal(t, rm.MemberCount(), 0)
}