Files
core/session/registry_test.go

561 lines
11 KiB
Go

package session
import (
"io"
"strconv"
"strings"
"testing"
"time"
"github.com/datarhei/core/v16/io/fs"
"github.com/lestrrat-go/strftime"
"github.com/stretchr/testify/require"
)
func TestRegister(t *testing.T) {
r, err := New(Config{})
require.NoError(t, err)
t.Cleanup(func() {
r.Close()
})
_, err = r.Register("", CollectorConfig{})
require.Error(t, err)
_, err = r.Register("../foo/bar", CollectorConfig{})
require.Error(t, err)
_, err = r.Register("foobar", CollectorConfig{})
require.NoError(t, err)
_, err = r.Register("foobar", CollectorConfig{})
require.Error(t, err)
}
func TestUnregister(t *testing.T) {
r, err := New(Config{})
require.NoError(t, err)
t.Cleanup(func() {
r.Close()
})
_, err = r.Register("foobar", CollectorConfig{})
require.NoError(t, err)
err = r.Unregister("foobar")
require.NoError(t, err)
err = r.Unregister("foobar")
require.Error(t, err)
}
func TestCollectors(t *testing.T) {
r, err := New(Config{})
require.NoError(t, err)
t.Cleanup(func() {
r.Close()
})
c := r.Collectors()
require.Equal(t, []string{}, c)
_, err = r.Register("foobar", CollectorConfig{})
require.NoError(t, err)
c = r.Collectors()
require.Equal(t, []string{"foobar"}, c)
err = r.Unregister("foobar")
require.NoError(t, err)
c = r.Collectors()
require.Equal(t, []string{}, c)
}
func TestGetCollector(t *testing.T) {
r, err := New(Config{})
require.NoError(t, err)
t.Cleanup(func() {
r.Close()
})
c := r.Collector("foobar")
require.Nil(t, c)
_, err = r.Register("foobar", CollectorConfig{})
require.NoError(t, err)
c = r.Collector("foobar")
require.NotNil(t, c)
err = r.Unregister("foobar")
require.NoError(t, err)
c = r.Collector("foobar")
require.Nil(t, c)
}
func TestUnregisterAll(t *testing.T) {
r, err := New(Config{})
require.NoError(t, err)
t.Cleanup(func() {
r.Close()
})
_, err = r.Register("foo", CollectorConfig{})
require.NoError(t, err)
_, err = r.Register("bar", CollectorConfig{})
require.NoError(t, err)
c := r.Collectors()
require.ElementsMatch(t, []string{"foo", "bar"}, c)
r.UnregisterAll()
c = r.Collectors()
require.Equal(t, []string{}, c)
}
func TestRestoreHistory(t *testing.T) {
memfs, err := fs.NewMemFilesystem(fs.MemConfig{})
require.NoError(t, err)
_, _, err = memfs.WriteFile("/foobar.json", []byte("{}"))
require.NoError(t, err)
r, err := New(Config{
PersistFS: memfs,
})
require.NoError(t, err)
t.Cleanup(func() {
r.Close()
})
c, err := r.Register("foobar", CollectorConfig{})
require.NoError(t, err)
c.RegisterAndActivate("foo", "ref", "location", "peer")
c.Egress("foo", 42)
err = r.Unregister("foobar")
require.NoError(t, err)
}
func TestRestoreInvalidHistory(t *testing.T) {
memfs, err := fs.NewMemFilesystem(fs.MemConfig{})
require.NoError(t, err)
_, _, err = memfs.WriteFile("/foobar.json", []byte(""))
require.NoError(t, err)
r, err := New(Config{
PersistFS: memfs,
})
require.NoError(t, err)
t.Cleanup(func() {
r.Close()
})
c, err := r.Register("foobar", CollectorConfig{})
require.NoError(t, err)
c.RegisterAndActivate("foo", "ref", "location", "peer")
c.Egress("foo", 42)
err = r.Unregister("foobar")
require.NoError(t, err)
files := memfs.List("/", fs.ListOptions{})
require.Equal(t, 2, len(files))
}
func TestPersistHistory(t *testing.T) {
memfs, err := fs.NewMemFilesystem(fs.MemConfig{})
require.NoError(t, err)
r, err := New(Config{
PersistFS: memfs,
})
require.NoError(t, err)
t.Cleanup(func() {
r.Close()
})
c, err := r.Register("foobar", CollectorConfig{})
require.NoError(t, err)
c.RegisterAndActivate("foo", "ref", "location", "peer")
c.Egress("foo", 42)
err = r.Unregister("foobar")
require.NoError(t, err)
_, err = memfs.Stat("/foobar.json")
require.NoError(t, err)
c, err = r.Register("foobar", CollectorConfig{})
require.NoError(t, err)
cc := c.(*collector)
totals, ok := cc.history.Sessions["location:peer:ref"]
require.True(t, ok)
require.Equal(t, "location", totals.Location)
require.Equal(t, "ref", totals.Reference)
require.Equal(t, "peer", totals.Peer)
require.Equal(t, uint64(42), totals.TotalTxBytes)
}
type slowMemFilesystem struct {
fs.Filesystem
}
func newSlowMemFilesystem(config fs.MemConfig) (fs.Filesystem, error) {
memfs, err := fs.NewMemFilesystem(config)
if err != nil {
return nil, err
}
f := &slowMemFilesystem{
Filesystem: memfs,
}
return f, nil
}
func (c *slowMemFilesystem) WriteFileSafe(path string, data []byte) (int64, bool, error) {
if path != "/foobar.json" {
return 0, true, nil
}
time.Sleep(2 * time.Second)
return c.Filesystem.WriteFileSafe(path, data)
}
func TestPersistHistorySlowSnapshot(t *testing.T) {
memfs, err := newSlowMemFilesystem(fs.MemConfig{})
require.NoError(t, err)
r, err := New(Config{
PersistFS: memfs,
})
require.NoError(t, err)
t.Cleanup(func() {
r.Close()
})
c, err := r.Register("foobar", CollectorConfig{})
require.NoError(t, err)
c.RegisterAndActivate("foo", "ref", "location", "peer")
c.Egress("foo", 42)
c.Close("foo")
err = r.Unregister("foobar")
require.NoError(t, err)
_, err = memfs.Stat("/foobar.json")
require.NoError(t, err)
}
func TestPeriodicPersistHistory(t *testing.T) {
memfs, err := fs.NewMemFilesystem(fs.MemConfig{})
require.NoError(t, err)
r, err := New(Config{
PersistFS: memfs,
PersistInterval: 5 * time.Second,
})
require.NoError(t, err)
t.Cleanup(func() {
r.Close()
})
c, err := r.Register("foobar", CollectorConfig{
SessionTimeout: time.Second,
})
require.NoError(t, err)
c.RegisterAndActivate("foo", "ref", "location", "peer")
c.Egress("foo", 42)
require.Eventually(t, func() bool {
_, err = memfs.Stat("/foobar.json")
return err == nil
}, 10*time.Second, time.Second)
err = r.Unregister("foobar")
require.NoError(t, err)
_, err = memfs.Stat("/foobar.json")
require.NoError(t, err)
}
func TestPersistSession(t *testing.T) {
memfs, err := fs.NewMemFilesystem(fs.MemConfig{})
require.NoError(t, err)
pattern := "/log/%Y-%m-%d.log"
r, err := New(Config{
PersistFS: memfs,
LogPattern: pattern,
})
require.NoError(t, err)
t.Cleanup(func() {
r.Close()
})
c, err := r.Register("foobar", CollectorConfig{
SessionTimeout: 3 * time.Second,
})
require.NoError(t, err)
c.RegisterAndActivate("foo", "ref", "location", "peer")
c.Egress("foo", 42)
err = r.Unregister("foobar")
require.NoError(t, err)
r.Close()
path, err := strftime.Format(pattern, time.Now())
require.NoError(t, err)
info, err := memfs.Stat(path)
require.NoError(t, err)
require.Greater(t, info.Size(), int64(0))
}
func TestPersistSessionDelayed(t *testing.T) {
memfs, err := fs.NewMemFilesystem(fs.MemConfig{})
require.NoError(t, err)
pattern := "/log/%Y-%m-%d-%H.log"
r, err := New(Config{
PersistFS: memfs,
LogPattern: pattern,
LogBufferDuration: 5 * time.Second,
})
require.NoError(t, err)
t.Cleanup(func() {
r.Close()
})
c, err := r.Register("foobar", CollectorConfig{
SessionTimeout: 3 * time.Second,
})
require.NoError(t, err)
ce, ok := c.(*collector)
require.True(t, ok)
start, err := time.Parse(time.RFC3339, "2023-11-01T15:04:00Z")
require.NoError(t, err)
ce.sessionsCh <- Session{
Collector: "foobar",
CreatedAt: start,
ClosedAt: start.Add(5 * time.Minute),
}
ce.sessionsCh <- Session{
Collector: "foobar",
CreatedAt: start,
ClosedAt: start.Add(6 * time.Minute),
}
ce.sessionsCh <- Session{
Collector: "foobar",
CreatedAt: start,
ClosedAt: start.Add(7 * time.Minute),
}
ce.sessionsCh <- Session{
Collector: "foobar",
CreatedAt: start,
ClosedAt: start.Add(1 * time.Hour),
}
// late entry
ce.sessionsCh <- Session{
Collector: "foobar",
CreatedAt: start,
ClosedAt: start.Add(8 * time.Minute),
}
ce.sessionsCh <- Session{
Collector: "foobar",
CreatedAt: start,
ClosedAt: start.Add(61 * time.Minute),
}
require.Eventually(t, func() bool {
path, err := strftime.Format(pattern, start)
if err != nil {
return false
}
_, err = memfs.Stat(path)
return err == nil
}, 10*time.Second, time.Second)
path, err := strftime.Format(pattern, start)
require.NoError(t, err)
file := memfs.Open(path)
require.NotNil(t, file)
data, err := io.ReadAll(file)
require.NoError(t, err)
file.Close()
lines := strings.Split(string(data), "\n")
require.Equal(t, 3, len(lines)-1)
require.Eventually(t, func() bool {
path, err := strftime.Format(pattern, start.Add(1*time.Hour))
if err != nil {
return false
}
_, err = memfs.Stat(path)
return err == nil
}, 10*time.Second, time.Second)
path, err = strftime.Format(pattern, start.Add(1*time.Hour))
require.NoError(t, err)
file = memfs.Open(path)
require.NotNil(t, file)
data, err = io.ReadAll(file)
require.NoError(t, err)
file.Close()
lines = strings.Split(string(data), "\n")
require.Equal(t, 3, len(lines)-1)
err = r.Unregister("foobar")
require.NoError(t, err)
}
func TestPersistSessionSlpit(t *testing.T) {
memfs, err := fs.NewMemFilesystem(fs.MemConfig{})
require.NoError(t, err)
pattern := "/log/%Y-%m-%d-%H:%M:%S.log"
r, err := New(Config{
PersistFS: memfs,
LogPattern: pattern,
})
require.NoError(t, err)
t.Cleanup(func() {
r.Close()
})
c, err := r.Register("foobar", CollectorConfig{
SessionTimeout: 3 * time.Second,
})
require.NoError(t, err)
c.RegisterAndActivate("foo", "ref", "location", "peer")
c.Egress("foo", 42)
time.Sleep(3 * time.Second)
c.RegisterAndActivate("bar", "ref", "location", "peer")
c.Egress("bar", 24)
err = r.Unregister("foobar")
require.NoError(t, err)
r.Close()
require.Equal(t, int64(2), memfs.Files())
}
func TestPersistSessionBuffer(t *testing.T) {
memfs, err := fs.NewMemFilesystem(fs.MemConfig{})
require.NoError(t, err)
pattern := "/log/%Y-%m-%d.log"
r, err := New(Config{
PersistFS: memfs,
LogPattern: pattern,
LogBufferDuration: 5 * time.Second,
})
require.NoError(t, err)
t.Cleanup(func() {
r.Close()
})
c, err := r.Register("foobar", CollectorConfig{
SessionTimeout: 3 * time.Second,
})
require.NoError(t, err)
c.RegisterAndActivate("foo", "ref", "location", "peer")
c.Egress("foo", 42)
require.Eventually(t, func() bool {
path, err := strftime.Format(pattern, time.Now())
if err != nil {
return false
}
_, err = memfs.Stat(path)
return err == nil
}, 10*time.Second, time.Second)
err = r.Unregister("foobar")
require.NoError(t, err)
r.Close()
path, err := strftime.Format(pattern, time.Now())
require.NoError(t, err)
info, err := memfs.Stat(path)
require.NoError(t, err)
require.Greater(t, info.Size(), int64(0))
}
func TestRegisterAfterCloseWithPersist(t *testing.T) {
memfs, err := fs.NewMemFilesystem(fs.MemConfig{})
require.NoError(t, err)
pattern := "/log/%Y-%m-%d.log"
r, err := New(Config{
PersistFS: memfs,
LogPattern: pattern,
LogBufferDuration: 5 * time.Second,
})
require.NoError(t, err)
t.Cleanup(func() {
r.Close()
})
c, err := r.Register("foobar", CollectorConfig{
SessionTimeout: 3 * time.Second,
})
require.NoError(t, err)
for i := 0; i < 1000; i++ {
c.RegisterAndActivate("foo_"+strconv.Itoa(i), "ref", "location", "peer")
c.Egress("foo", int64(i))
}
r.Close()
c.RegisterAndActivate("foo_XXX", "ref", "location", "peer")
c.Egress("foo", 42)
time.Sleep(5 * time.Second)
require.Equal(t, int64(2), memfs.Files())
}