v0.33.1 9577fee

session_test.go RawHistoryFolder

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}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close