Smail/test/backend/runtime_logs_test.go
smail 5faadcd6eb
Some checks are pending
Security Checks / security (push) Waiting to run
保存三数据库日志与三十天清理实现,继续补充验收
2026-09-08 22:30:50 +08:00

96 lines
2.7 KiB
Go

package runtimelog
import (
"context"
"os"
"path/filepath"
"strings"
"testing"
"time"
"git.pcux.cn/xuans/Smail/utils/logpolicy"
)
func TestRuntimeLogCompressionAndExactRetention(t *testing.T) {
root := t.TempDir()
w, err := New(root)
if err != nil {
t.Fatal(err)
}
defer w.Close()
now := time.Date(2026, 9, 8, 12, 0, 0, 0, time.UTC)
cutoff := logpolicy.Cutoff(now)
w.now = func() time.Time { return cutoff }
for _, at := range []time.Time{cutoff.Add(-time.Hour), cutoff, cutoff.Add(time.Hour), now.Add(-8 * 24 * time.Hour), now} {
if err := w.WriteAt(at, "sample\nsecond line"); err != nil {
t.Fatal(err)
}
}
w.now = func() time.Time { return now }
ctx := context.Background()
if err := w.Maintain(ctx, now); err != nil {
t.Fatal(err)
}
files, err := w.Files()
if err != nil || len(files) != 3 {
t.Fatalf("files: %+v %v", files, err)
}
name := prefix + cutoff.Format("2006-01-02") + ".log.gz"
page, err := w.Read(ctx, name, 0, 100)
if err != nil || len(page.Lines) != 2 {
t.Fatalf("boundary: %+v %v", page, err)
}
if !strings.Contains(page.Lines[0], `\n`) {
t.Fatal("multiline event split")
}
// 压缩后仍须逐条裁剪,不能按整个归档日期删除有效记录。
now = now.Add(30 * time.Minute)
if err := w.Maintain(ctx, now); err != nil {
t.Fatal(err)
}
page, err = w.Read(ctx, name, 0, 100)
if err != nil || len(page.Lines) != 1 {
t.Fatalf("compressed boundary: %+v %v", page, err)
}
now = now.Add(24 * time.Hour)
if err := w.Maintain(ctx, now); err != nil {
t.Fatal(err)
}
if _, err := w.root.Stat(name); !os.IsNotExist(err) {
t.Fatalf("expired archive still exists: %v", err)
}
if _, err := w.Read(ctx, "../config/config.json", 0, 100); err == nil {
t.Fatal("path traversal accepted")
}
if err := w.Maintain(ctx, now); err != nil {
t.Fatal(err)
}
}
func TestRuntimeLogCorruptionAndUnknownFilesArePreserved(t *testing.T) {
root := t.TempDir()
w, err := New(root)
if err != nil {
t.Fatal(err)
}
defer w.Close()
now := time.Now().UTC()
w.now = func() time.Time { return now }
directory := filepath.Join(root, "log", "运行日志")
name := prefix + now.Add(-40*24*time.Hour).Format("2006-01-02") + ".log.gz"
if err := os.WriteFile(filepath.Join(directory, name), []byte("broken"), 0600); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(directory, "manual.log"), []byte("keep"), 0600); err != nil {
t.Fatal(err)
}
if err := w.Maintain(context.Background(), now); err == nil {
t.Fatal("corruption not reported")
}
for _, file := range []string{name, "manual.log"} {
if _, err := os.Stat(filepath.Join(directory, file)); err != nil {
t.Fatal("unmanaged or damaged evidence deleted")
}
}
}