You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
3.4 KiB

package logstorage
import (
"bytes"
"os"
"strings"
"testing"
"time"
)
func TestClearSystemPreservesOtherClassesAndReclaimsStoredData(t *testing.T) {
root := t.TempDir()
s := openTestStore(t, Options{Root: root})
now := time.Now()
for i := 0; i < 2; i++ {
if _, err := s.Append(ClassSystem, now, map[string]string{"message": strings.Repeat("old-system", 1000)}); err != nil {
t.Fatal(err)
}
}
for _, class := range []string{ClassAudit, ClassPort, ClassLink} {
if _, err := s.Append(class, now, map[string]string{"message": "keep"}); err != nil {
t.Fatal(err)
}
}
if err := s.ApplyRetention(Retention{365, 365, 365}); err != nil {
t.Fatal(err)
}
if _, err := s.Append(ClassSystem, now, map[string]string{"message": "active-system"}); err != nil {
t.Fatal(err)
}
before, err := s.Snapshot()
if err != nil {
t.Fatal(err)
}
if n, err := s.ClearSystem(); err != nil || n != 4 {
t.Fatalf("clear=%d,%v", n, err)
}
after, err := s.Snapshot()
if err != nil {
t.Fatal(err)
}
if after.UsageBytes["system"] >= before.UsageBytes["system"] {
t.Fatal("physical storage did not decrease")
}
paths, _ := s.closedSegmentsLocked(ClassSystem)
paths = append(paths, s.activePath(ClassSystem))
for _, path := range paths {
data, err := os.ReadFile(path)
if err != nil || bytes.Contains(data, []byte("system")) {
t.Fatalf("cleared bytes remain: %s,%v", path, err)
}
}
s = openTestStore(t, Options{Root: root})
for _, class := range []string{ClassAudit, ClassPort, ClassLink} {
rows, err := s.Read(class)
want := 1
if class == ClassAudit {
want = 0
}
if err != nil || len(rows) != want {
t.Fatalf("%s changed: %s,%v", class, rows, err)
}
}
page, err := s.Page(ClassSystem, 0, 500)
if err != nil || len(page) != 0 {
t.Fatalf("deleted data returned: %v,%v", page, err)
}
event, err := s.Append(ClassSystem, now, map[string]string{"message": "new"})
if err != nil || event.Sequence != 4 {
t.Fatalf("sequence=%v,%v", event, err)
}
var output bytes.Buffer
if err := s.Export(ClassSystem, &output); err != nil || strings.Contains(output.String(), "old-system") {
t.Fatal("export resurrected data", err)
}
if n, err := s.ClearSystem(); err != nil || n != 1 {
t.Fatalf("second clear=%d,%v", n, err)
}
}
func TestClearSystemRecoversCheckpointBeforeCompaction(t *testing.T) {
root := t.TempDir()
s := openTestStore(t, Options{Root: root})
if _, err := s.Append(ClassSystem, time.Now(), map[string]string{"message": "old"}); err != nil {
t.Fatal(err)
}
original, err := os.ReadFile(s.activePath(ClassSystem))
if err != nil {
t.Fatal(err)
}
if _, err := s.ClearSystem(); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(s.activePath(ClassSystem), original, 0o600); err != nil {
t.Fatal(err)
}
s = openTestStore(t, Options{Root: root})
rows, err := s.Read(ClassSystem)
if err != nil || len(rows) != 0 {
t.Fatal("crash resurrected records", err)
}
next, err := s.Append(ClassSystem, time.Now(), map[string]string{"message": "new"})
if err != nil || next.Sequence != 2 {
t.Fatal("sequence reused", err)
}
}
func TestSystemClearFailsClosedOnInvalidCheckpoint(t *testing.T) {
root := t.TempDir()
s := openTestStore(t, Options{Root: root})
if err := os.Mkdir(s.systemClearPath(), 0o700); err != nil {
t.Fatal(err)
}
if _, err := s.ClearSystem(); err == nil {
t.Fatal("unwritable checkpoint accepted")
}
if _, err := Open(Options{Root: root}); err == nil {
t.Fatal("invalid checkpoint accepted on restart")
}
}