Embeds a DB-IP Lite country MMDB (~5MB) in the binary via go:embed, keeping the single-binary deployment story clean. Country codes are stored alongside login attempts and sessions, shown in the dashboard (Top IPs, Top Countries card, Recent/Active Sessions, session detail). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
81 lines
1.9 KiB
Go
81 lines
1.9 KiB
Go
package shell
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.t-juice.club/torjus/oubliette/internal/storage"
|
|
)
|
|
|
|
func TestEventRecorderFlush(t *testing.T) {
|
|
store := storage.NewMemoryStore()
|
|
ctx := context.Background()
|
|
|
|
// Create a session so events have a valid session ID.
|
|
id, err := store.CreateSession(ctx, "10.0.0.1", "root", "bash", "")
|
|
if err != nil {
|
|
t.Fatalf("CreateSession: %v", err)
|
|
}
|
|
|
|
rec := NewEventRecorder(id, store, slog.Default())
|
|
rec.Start(ctx)
|
|
|
|
// Record some events.
|
|
now := time.Now()
|
|
rec.RecordEvent(now, 0, []byte("hello"))
|
|
rec.RecordEvent(now.Add(100*time.Millisecond), 1, []byte("world"))
|
|
|
|
// Close should trigger final flush.
|
|
rec.Close()
|
|
|
|
events, err := store.GetSessionEvents(ctx, id)
|
|
if err != nil {
|
|
t.Fatalf("GetSessionEvents: %v", err)
|
|
}
|
|
if len(events) != 2 {
|
|
t.Fatalf("len = %d, want 2", len(events))
|
|
}
|
|
if string(events[0].Data) != "hello" {
|
|
t.Errorf("events[0].Data = %q, want %q", events[0].Data, "hello")
|
|
}
|
|
if events[0].Direction != 0 {
|
|
t.Errorf("events[0].Direction = %d, want 0", events[0].Direction)
|
|
}
|
|
if string(events[1].Data) != "world" {
|
|
t.Errorf("events[1].Data = %q, want %q", events[1].Data, "world")
|
|
}
|
|
if events[1].Direction != 1 {
|
|
t.Errorf("events[1].Direction = %d, want 1", events[1].Direction)
|
|
}
|
|
}
|
|
|
|
func TestEventRecorderPeriodicFlush(t *testing.T) {
|
|
store := storage.NewMemoryStore()
|
|
ctx := context.Background()
|
|
|
|
id, err := store.CreateSession(ctx, "10.0.0.1", "root", "bash", "")
|
|
if err != nil {
|
|
t.Fatalf("CreateSession: %v", err)
|
|
}
|
|
|
|
rec := NewEventRecorder(id, store, slog.Default())
|
|
rec.Start(ctx)
|
|
|
|
// Record an event and wait for the periodic flush (2s + some margin).
|
|
rec.RecordEvent(time.Now(), 1, []byte("periodic"))
|
|
|
|
time.Sleep(3 * time.Second)
|
|
|
|
events, err := store.GetSessionEvents(ctx, id)
|
|
if err != nil {
|
|
t.Fatalf("GetSessionEvents: %v", err)
|
|
}
|
|
if len(events) != 1 {
|
|
t.Errorf("expected periodic flush, got %d events", len(events))
|
|
}
|
|
|
|
rec.Close()
|
|
}
|