1package logging
2
3import (
4 "os"
5 "path/filepath"
6 "testing"
7 "time"
8)
9
10func TestCleanupSessionLogFiles_RemovesOldestSessionLogs(t *testing.T) {
11 t.Parallel()
12
13 dir := t.TempDir()
14 base := time.Date(2026, 4, 24, 12, 0, 0, 0, time.UTC)
15
16 oldest := writeSessionLog(t, dir, "20260424_120000_0001", base)
17 secondOldest := writeSessionLog(t, dir, "20260424_120001_0002", base.Add(time.Second))
18 secondNewest := writeSessionLog(t, dir, "20260424_120002_0003", base.Add(2*time.Second))
19 newest := writeSessionLog(t, dir, "20260424_120003_0004", base.Add(3*time.Second))
20 nonSession := filepath.Join(dir, "dumber.log")
21 if err := os.WriteFile(nonSession, []byte("keep me"), 0o644); err != nil {
22 t.Fatalf("write non-session log: %v", err)
23 }
24
25 removed, err := CleanupSessionLogFiles(dir, 2)
26 if err != nil {
27 t.Fatalf("cleanup session log files: %v", err)
28 }
29 if removed != 2 {
30 t.Fatalf("removed = %d, want 2", removed)
31 }
32
33 assertMissing(t, oldest)
34 assertMissing(t, secondOldest)
35 assertExists(t, secondNewest)
36 assertExists(t, newest)
37 assertExists(t, nonSession)
38}
39
40func TestCleanupSessionLogFiles_DisabledWhenMaxFilesZero(t *testing.T) {
41 t.Parallel()
42
43 dir := t.TempDir()
44 path := writeSessionLog(t, dir, "20260424_120000_0001", time.Now())
45
46 removed, err := CleanupSessionLogFiles(dir, 0)
47 if err != nil {
48 t.Fatalf("cleanup session log files: %v", err)
49 }
50 if removed != 0 {
51 t.Fatalf("removed = %d, want 0", removed)
52 }
53 assertExists(t, path)
54}
55
56func TestCleanupSessionLogFiles_NoRemovalWhenUnderLimit(t *testing.T) {
57 t.Parallel()
58
59 dir := t.TempDir()
60 base := time.Date(2026, 4, 24, 12, 0, 0, 0, time.UTC)
61
62 first := writeSessionLog(t, dir, "20260424_120000_0001", base)
63 second := writeSessionLog(t, dir, "20260424_120001_0002", base.Add(time.Second))
64
65 removed, err := CleanupSessionLogFiles(dir, 3)
66 if err != nil {
67 t.Fatalf("cleanup session log files: %v", err)
68 }
69 if removed != 0 {
70 t.Fatalf("removed = %d, want 0", removed)
71 }
72
73 assertExists(t, first)
74 assertExists(t, second)
75}
76
77func TestCleanupSessionLogFiles_UsesFilenameTiebreakerForEqualModTimes(t *testing.T) {
78 t.Parallel()
79
80 dir := t.TempDir()
81 base := time.Date(2026, 4, 24, 12, 0, 0, 0, time.UTC)
82
83 oldestByName := writeSessionLog(t, dir, "20260424_120000_0001", base)
84 keptByName := writeSessionLog(t, dir, "20260424_120000_0002", base)
85 newestByName := writeSessionLog(t, dir, "20260424_120000_0003", base)
86
87 removed, err := CleanupSessionLogFiles(dir, 2)
88 if err != nil {
89 t.Fatalf("cleanup session log files: %v", err)
90 }
91 if removed != 1 {
92 t.Fatalf("removed = %d, want 1", removed)
93 }
94
95 assertMissing(t, oldestByName)
96 assertExists(t, keptByName)
97 assertExists(t, newestByName)
98}
99
100func TestCleanupSessionLogFiles_KeepsSpecifiedSessionWithinLimit(t *testing.T) {
101 t.Parallel()
102
103 dir := t.TempDir()
104 base := time.Date(2026, 4, 24, 12, 0, 0, 0, time.UTC)
105 keepID := "20260424_120000_0001"
106
107 oldestKept := writeSessionLog(t, dir, keepID, base)
108 middle := writeSessionLog(t, dir, "20260424_120001_0002", base.Add(time.Second))
109 newest := writeSessionLog(t, dir, "20260424_120002_0003", base.Add(2*time.Second))
110
111 removed, err := CleanupSessionLogFiles(dir, 1, keepID)
112 if err != nil {
113 t.Fatalf("cleanup session log files: %v", err)
114 }
115 if removed != 2 {
116 t.Fatalf("removed = %d, want 2", removed)
117 }
118
119 assertExists(t, oldestKept)
120 assertMissing(t, middle)
121 assertMissing(t, newest)
122}
123
124func TestCleanupSessionLogFiles_BoundsSpecifiedSessionsToMaxFiles(t *testing.T) {
125 t.Parallel()
126
127 dir := t.TempDir()
128 base := time.Date(2026, 4, 24, 12, 0, 0, 0, time.UTC)
129
130 oldestKeptID := "20260424_120000_0001"
131 middleKeptID := "20260424_120001_0002"
132 newestKeptID := "20260424_120002_0003"
133 oldestKept := writeSessionLog(t, dir, oldestKeptID, base)
134 middleKept := writeSessionLog(t, dir, middleKeptID, base.Add(time.Second))
135 newestKept := writeSessionLog(t, dir, newestKeptID, base.Add(2*time.Second))
136
137 removed, err := CleanupSessionLogFiles(dir, 2, oldestKeptID, middleKeptID, newestKeptID)
138 if err != nil {
139 t.Fatalf("cleanup session log files: %v", err)
140 }
141 if removed != 1 {
142 t.Fatalf("removed = %d, want 1", removed)
143 }
144
145 assertMissing(t, oldestKept)
146 assertExists(t, middleKept)
147 assertExists(t, newestKept)
148}
149
150func TestCleanupSessionLogFiles_MissingDirectoryIsNoop(t *testing.T) {
151 t.Parallel()
152
153 removed, err := CleanupSessionLogFiles(filepath.Join(t.TempDir(), "missing"), 2)
154 if err != nil {
155 t.Fatalf("cleanup session log files: %v", err)
156 }
157 if removed != 0 {
158 t.Fatalf("removed = %d, want 0", removed)
159 }
160}
161
162func writeSessionLog(t *testing.T, dir, sessionID string, modTime time.Time) string {
163 t.Helper()
164
165 path := filepath.Join(dir, SessionFilename(sessionID))
166 if err := os.WriteFile(path, []byte(sessionID), 0o644); err != nil {
167 t.Fatalf("write session log %s: %v", sessionID, err)
168 }
169 if err := os.Chtimes(path, modTime, modTime); err != nil {
170 t.Fatalf("set mod time for %s: %v", sessionID, err)
171 }
172 return path
173}
174
175func assertExists(t *testing.T, path string) {
176 t.Helper()
177 if _, err := os.Stat(path); err != nil {
178 t.Fatalf("expected %s to exist: %v", path, err)
179 }
180}
181
182func assertMissing(t *testing.T, path string) {
183 t.Helper()
184 if _, err := os.Stat(path); !os.IsNotExist(err) {
185 t.Fatalf("expected %s to be removed, stat err = %v", path, err)
186 }
187}