1package bootstrap
2
3import (
4 "os"
5 "path/filepath"
6 "testing"
7 "time"
8
9 "github.com/stretchr/testify/assert"
10 "github.com/stretchr/testify/require"
11)
12
13func TestSessionMarkers_WriteStartupAndShutdown(t *testing.T) {
14 lockDir := t.TempDir()
15 sessionID := "s123"
16 startedAt := time.Date(2026, 2, 7, 10, 0, 0, 0, time.UTC)
17 endedAt := startedAt.Add(3 * time.Minute)
18
19 err := writeStartupMarker(lockDir, sessionID, startedAt)
20 require.NoError(t, err)
21
22 startupContent, err := os.ReadFile(startupMarkerPath(lockDir, sessionID))
23 require.NoError(t, err)
24 assert.Contains(t, string(startupContent), startedAt.Format(time.RFC3339Nano))
25 assert.Contains(t, string(startupContent), "pid=")
26 assert.Contains(t, string(startupContent), "ppid=")
27
28 err = writeShutdownMarker(lockDir, sessionID, endedAt)
29 require.NoError(t, err)
30
31 shutdownContent, err := os.ReadFile(shutdownMarkerPath(lockDir, sessionID))
32 require.NoError(t, err)
33 assert.Contains(t, string(shutdownContent), endedAt.Format(time.RFC3339Nano))
34 assert.Contains(t, string(shutdownContent), "started_at="+startedAt.Format(time.RFC3339Nano))
35 assert.Contains(t, string(shutdownContent), "pid=")
36 assert.Contains(t, string(shutdownContent), "ppid=")
37}
38
39func TestSessionMarkers_MarkAbruptExits(t *testing.T) {
40 lockDir := t.TempDir()
41 detectedAt := time.Date(2026, 2, 7, 11, 0, 0, 0, time.UTC)
42
43 require.NoError(t, writeStartupMarker(lockDir, "abrupt-a", detectedAt.Add(-5*time.Minute)))
44 require.NoError(t, writeStartupMarker(lockDir, "clean-b", detectedAt.Add(-4*time.Minute)))
45 require.NoError(t, writeShutdownMarker(lockDir, "clean-b", detectedAt.Add(-1*time.Minute)))
46
47 abruptSessions, err := markAbruptExits(lockDir, detectedAt, nil)
48 require.NoError(t, err)
49 assert.Equal(t, []string{"abrupt-a"}, abruptSessions)
50
51 abruptMarkerData, err := os.ReadFile(abruptMarkerPath(lockDir, "abrupt-a"))
52 require.NoError(t, err)
53 assert.Contains(t, string(abruptMarkerData), "detected_at="+detectedAt.Format(time.RFC3339Nano))
54 assert.Contains(t, string(abruptMarkerData), "started_at=")
55 assert.Contains(t, string(abruptMarkerData), "pid=")
56 assert.Contains(t, string(abruptMarkerData), "ppid=")
57 assert.FileExists(t, filepath.Join(lockDir, "session_clean-b.shutdown.marker"))
58}
59
60func TestSessionMarkers_MarkAbruptExitsIdempotent(t *testing.T) {
61 lockDir := t.TempDir()
62 detectedAt := time.Date(2026, 2, 7, 12, 0, 0, 0, time.UTC)
63
64 require.NoError(t, writeStartupMarker(lockDir, "abrupt-c", detectedAt.Add(-10*time.Minute)))
65
66 first, err := markAbruptExits(lockDir, detectedAt, nil)
67 require.NoError(t, err)
68 assert.Equal(t, []string{"abrupt-c"}, first)
69
70 second, err := markAbruptExits(lockDir, detectedAt.Add(1*time.Minute), nil)
71 require.NoError(t, err)
72 assert.Empty(t, second)
73}