131 lines
3.1 KiB
Go
131 lines
3.1 KiB
Go
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package eventlog
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
"testing"
|
|
)
|
|
|
|
func TestWriterAppendsJSONLWithPrivatePermissions(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "state", "events.jsonl")
|
|
writer, err := New(path, 1<<20)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, record := range []map[string]any{
|
|
{"event_type": "status", "sequence": 1},
|
|
{"event_type": "alert", "sequence": 2},
|
|
} {
|
|
if err := writer.Append(record); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
rows := readRows(t, path)
|
|
if len(rows) != 2 || rows[0]["sequence"] != float64(1) || rows[1]["sequence"] != float64(2) {
|
|
t.Fatalf("rows=%#v", rows)
|
|
}
|
|
info, err := os.Stat(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := info.Mode().Perm(); got != 0o600 {
|
|
t.Fatalf("mode=%#o", got)
|
|
}
|
|
}
|
|
|
|
func TestWriterRotatesBeforeCrossingBound(t *testing.T) {
|
|
directory := t.TempDir()
|
|
path := filepath.Join(directory, "events.jsonl")
|
|
first := map[string]any{"event_type": "status", "marker": "first"}
|
|
encoded, err := json.Marshal(first)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
writer, err := New(path, int64(len(encoded)+1))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := writer.Append(first); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := writer.Append(map[string]any{"event_type": "alert", "marker": "second"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
current := readRows(t, path)
|
|
rotated := readRows(t, path+".1")
|
|
if len(current) != 1 || current[0]["marker"] != "second" {
|
|
t.Fatalf("current=%#v", current)
|
|
}
|
|
if len(rotated) != 1 || rotated[0]["marker"] != "first" {
|
|
t.Fatalf("rotated=%#v", rotated)
|
|
}
|
|
}
|
|
|
|
func TestWriterSerializesConcurrentAppends(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "events.jsonl")
|
|
writer, err := New(path, 1<<20)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var wait sync.WaitGroup
|
|
for index := range 32 {
|
|
wait.Add(1)
|
|
go func() {
|
|
defer wait.Done()
|
|
if err := writer.Append(map[string]any{"event_type": "status", "sequence": index}); err != nil {
|
|
t.Errorf("append: %v", err)
|
|
}
|
|
}()
|
|
}
|
|
wait.Wait()
|
|
if rows := readRows(t, path); len(rows) != 32 {
|
|
t.Fatalf("row count=%d", len(rows))
|
|
}
|
|
}
|
|
|
|
func TestNewRejectsInvalidConfiguration(t *testing.T) {
|
|
if _, err := New("", 100); err == nil {
|
|
t.Fatal("empty path accepted")
|
|
}
|
|
if _, err := New(filepath.Join(t.TempDir(), "events.jsonl"), 0); err == nil {
|
|
t.Fatal("zero bound accepted")
|
|
}
|
|
}
|
|
|
|
func TestWriterRejectsRecordLargerThanReaderLimit(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "events.jsonl")
|
|
writer, err := New(path, 2<<20)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := writer.Append(map[string]any{"event_type": "alert", "payload": make([]byte, maxRecordBytes)}); err == nil {
|
|
t.Fatal("oversized record accepted")
|
|
}
|
|
}
|
|
|
|
func readRows(t *testing.T, path string) []map[string]any {
|
|
t.Helper()
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer file.Close()
|
|
var rows []map[string]any
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
var row map[string]any
|
|
if err := json.Unmarshal(scanner.Bytes(), &row); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
rows = append(rows, row)
|
|
}
|
|
if err := scanner.Err(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return rows
|
|
}
|