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 != 3 { 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) if err != nil || len(rows) != 1 { 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") } }