Files
go-mana-prism/embassy_test.go
T
2026-05-10 18:47:18 -04:00

351 lines
7.4 KiB
Go

package prism
import (
"context"
"git.wisehodl.dev/jay/go-honeybee"
"github.com/stretchr/testify/assert"
"testing"
"time"
)
func TestEmbassyPoolEvents(t *testing.T) {
ctx := context.Background()
eventsCh := make(chan honeybee.OutboundPoolEvent)
pool := EmbassyPlugin{
Connect: func(id string) error { return nil },
Remove: func(id string) error { return nil },
Send: func(id string, data []byte) error { return nil },
Events: eventsCh,
}
e := NewEmbassy(ctx, pool, nil, nil)
sub := e.Subscribe()
t.Run("added then removed", func(t *testing.T) {
err := e.Dispatch("wss://test")
assert.NoError(t, err)
Eventually(t, func() bool {
select {
default:
return false
case ev := <-sub:
return ev.Kind == EventAdded
}
}, "expected added event")
err = e.Dismiss("wss://test")
assert.NoError(t, err)
Eventually(t, func() bool {
select {
default:
return false
case ev := <-sub:
return ev.Kind == EventRemoved
}
}, "expected removed event")
})
t.Run("connected", func(t *testing.T) {
e.Dispatch("wss://test")
eventsCh <- honeybee.OutboundPoolEvent{
ID: "wss://test",
Kind: honeybee.OutboundEventConnected,
At: time.Now(),
}
Eventually(t, func() bool {
select {
default:
return false
case ev := <-sub:
return ev.Kind == EventConnected
}
}, "expected connected event")
})
t.Run("disconnected", func(t *testing.T) {
e.Dispatch("wss://test")
eventsCh <- honeybee.OutboundPoolEvent{
ID: "wss://test",
Kind: honeybee.OutboundEventDisconnected,
At: time.Now(),
}
Eventually(t, func() bool {
select {
default:
return false
case ev := <-sub:
return ev.Kind == EventDisconnected
}
}, "expected disconnected event")
})
}
func TestEmbassyPeerRegistry(t *testing.T) {
ctx := context.Background()
eventsCh := make(chan honeybee.OutboundPoolEvent)
pool := EmbassyPlugin{
Connect: func(id string) error { return nil },
Remove: func(id string) error { return nil },
Send: func(id string, data []byte) error { return nil },
Events: eventsCh,
}
e := NewEmbassy(ctx, pool, nil, nil)
// add
e.Dispatch("wss://test")
url, ok := e.HasPeer("wss://test/")
assert.Equal(t, "wss://test", url)
assert.True(t, ok)
assert.False(t, e.IsConnected("wss://test"))
// connect
eventsCh <- honeybee.OutboundPoolEvent{
ID: "wss://test",
Kind: honeybee.OutboundEventConnected,
At: time.Now(),
}
Eventually(t, func() bool {
_, exists := e.HasPeer("wss://test")
connected := e.IsConnected("wss://test")
return exists && connected
}, "expected: exists, connected")
// disconnect
eventsCh <- honeybee.OutboundPoolEvent{
ID: "wss://test",
Kind: honeybee.OutboundEventDisconnected,
At: time.Now(),
}
Eventually(t, func() bool {
_, exists := e.HasPeer("wss://test")
connected := e.IsConnected("wss://test")
return exists && !connected
}, "expected: exists, disconnected")
// remove
e.Dismiss("wss://test")
_, ok = e.HasPeer("wss://test")
assert.False(t, ok)
assert.False(t, e.IsConnected("wss://test"))
}
func TestEmbassyPeers(t *testing.T) {
ctx := context.Background()
pool := EmbassyPlugin{
Connect: func(id string) error { return nil },
Remove: func(id string) error { return nil },
Send: func(id string, data []byte) error { return nil },
Events: nil,
}
e := NewEmbassy(ctx, pool, nil, nil)
assert.Len(t, e.Peers(), 0)
e.Dispatch("wss://test1")
e.Dispatch("wss://test2")
assert.Len(t, e.Peers(), 2)
e.Dismiss("wss://test2")
assert.Len(t, e.Peers(), 1)
}
func TestEmbassySubFanout(t *testing.T) {
ctx := context.Background()
eventsCh := make(chan honeybee.OutboundPoolEvent)
pool := EmbassyPlugin{
Connect: func(id string) error { return nil },
Remove: func(id string) error { return nil },
Send: func(id string, data []byte) error { return nil },
Events: eventsCh,
}
e := NewEmbassy(ctx, pool, nil, nil)
sub1 := e.Subscribe()
sub2 := e.Subscribe()
e.Dispatch("wss://test")
Eventually(t, func() bool {
select {
default:
return false
case ev := <-sub1:
return ev.Kind == EventAdded
}
}, "expected added event on sub1")
Eventually(t, func() bool {
select {
default:
return false
case ev := <-sub2:
return ev.Kind == EventAdded
}
}, "expected added event on sub2")
}
func TestEmbassyClose(t *testing.T) {
ctx := context.Background()
eventsCh := make(chan honeybee.OutboundPoolEvent, 1)
pool := EmbassyPlugin{
Connect: func(id string) error { return nil },
Remove: func(id string) error { return nil },
Send: func(id string, data []byte) error { return nil },
Events: eventsCh,
}
e := NewEmbassy(ctx, pool, nil, nil)
sub1 := e.Subscribe()
sub2 := e.Subscribe()
e.Dispatch("wss://test")
e.Close()
// peer gets removed
Eventually(t, func() bool {
select {
default:
return false
case ev := <-sub1:
return ev.ID == "wss://test" && ev.Kind == EventRemoved
}
}, "expected peer removed")
Eventually(t, func() bool {
select {
default:
return false
case ev := <-sub2:
return ev.ID == "wss://test" && ev.Kind == EventRemoved
}
}, "expected peer removed")
// peer list is empty
_, ok := e.HasPeer("wss://test")
assert.False(t, ok)
assert.Len(t, e.Peers(), 0)
// subs close
Eventually(t, func() bool {
_, ok1 := <-sub1
_, ok2 := <-sub2
return !ok1 && !ok2
}, "subs should close")
}
func TestEmbassyJournals(t *testing.T) {
ctx := context.Background()
jc := NewJournalCollector()
eventsCh := make(chan honeybee.OutboundPoolEvent, 1)
pool := EmbassyPlugin{
Connect: func(id string) error { return nil },
Remove: func(id string) error { return nil },
Send: func(id string, data []byte) error { return nil },
Events: eventsCh,
}
e := NewEmbassy(ctx, pool, jc, nil)
out := jc.Out()
peer := "wss://test"
// added
e.Dispatch(peer)
Eventually(t, func() bool {
select {
case entry := <-out:
_, ok := entry.(PeerAddedJournal)
return ok
default:
return false
}
}, "expected PeerAddedJournal")
// connected
eventsCh <- honeybee.OutboundPoolEvent{
ID: peer,
Kind: honeybee.OutboundEventConnected,
At: time.Now(),
}
Eventually(t, func() bool {
select {
case entry := <-out:
e, ok := entry.(PeerConnectedJournal)
// ensure fields are correct
peerOk := e.PeerID() == "wss://test"
modOk := e.Component().Module() == "prism"
pathOk := e.Component().PathString() == "embassy"
return ok && peerOk && modOk && pathOk
default:
return false
}
}, "expected PeerConnectedJournal")
// disconnected
eventsCh <- honeybee.OutboundPoolEvent{
ID: peer,
Kind: honeybee.OutboundEventDisconnected,
At: time.Now(),
}
Eventually(t, func() bool {
select {
case entry := <-out:
_, ok := entry.(PeerDisconnectedJournal)
return ok
default:
return false
}
}, "expected PeerDisconnectedJournal")
// removed
e.Dismiss(peer)
Eventually(t, func() bool {
select {
case entry := <-out:
_, ok := entry.(PeerRemovedJournal)
return ok
default:
return false
}
}, "expected PeerRemovedJournal")
// close embassy: closes journal channel
e.Close()
// Ensure jc can close now that embassy has closed its journal channel
jcClosed := make(chan struct{})
go func() {
jc.Close()
close(jcClosed)
}()
Eventually(t, func() bool {
select {
case <-jcClosed:
return true
default:
return false
}
}, "JournalCollector.Close() should return after Embassy.Close()")
}