This commit is contained in:
2026-06-23 05:02:15 +08:00
commit e6f1776d4f
264 changed files with 54215 additions and 0 deletions
@@ -0,0 +1,245 @@
package cc
import (
"context"
"os"
"path/filepath"
"testing"
"time"
)
// --- pure UUID extraction tests ---
func TestExtractIDFromRolloutFilename(t *testing.T) {
cases := []struct {
name string
want string
}{
{
"rollout-2026-04-27T02-57-26-019dcb27-58a6-70a1-a5d1-bfc7f3ed9d0a.jsonl",
"019dcb27-58a6-70a1-a5d1-bfc7f3ed9d0a",
},
{
"rollout-2026-01-01T00-00-00-aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee.jsonl",
"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
},
{
// No UUID — should return empty string.
"rollout-2026-04-27T02-57-26.jsonl",
"",
},
{
// Not a rollout file.
"session.jsonl",
"",
},
}
for _, tc := range cases {
got := extractIDFromRolloutFilename(tc.name)
if got != tc.want {
t.Errorf("extractIDFromRolloutFilename(%q) = %q, want %q", tc.name, got, tc.want)
}
}
}
func TestCodexSessionsDir(t *testing.T) {
ts := time.Date(2026, 4, 27, 2, 57, 26, 0, time.UTC)
got := CodexSessionsDir("/home/alice", ts)
want := "/home/alice/.codex/sessions/2026/04/27"
if got != want {
t.Errorf("CodexSessionsDir = %q, want %q", got, want)
}
}
// --- watcher tests ---
func TestWatchForNewCodexSession_DetectsRolloutByFilename(t *testing.T) {
dir := t.TempDir()
ctx := context.Background()
ch := make(chan struct {
id string
err error
}, 1)
go func() {
id, err := WatchForNewCodexSession(ctx, CodexSessionWatchOpts{
SessionsDir: dir,
Timeout: 2 * time.Second,
})
ch <- struct {
id string
err error
}{id, err}
}()
time.Sleep(50 * time.Millisecond)
uuid := "019dcb27-58a6-70a1-a5d1-bfc7f3ed9d0a"
fname := "rollout-2026-04-27T02-57-26-" + uuid + ".jsonl"
f, err := os.Create(filepath.Join(dir, fname))
if err != nil {
t.Fatal(err)
}
f.Close()
r := <-ch
if r.err != nil {
t.Fatalf("unexpected error: %v", r.err)
}
if r.id != uuid {
t.Errorf("got id %q, want %q", r.id, uuid)
}
}
func TestWatchForNewCodexSession_FallbackToFirstLine(t *testing.T) {
dir := t.TempDir()
ctx := context.Background()
ch := make(chan struct {
id string
err error
}, 1)
go func() {
id, err := WatchForNewCodexSession(ctx, CodexSessionWatchOpts{
SessionsDir: dir,
Timeout: 2 * time.Second,
})
ch <- struct {
id string
err error
}{id, err}
}()
time.Sleep(50 * time.Millisecond)
// File name without a UUID — triggers first-line fallback.
wantID := "fallback-thread-id-0001"
fname := "rollout-2026-04-27T02-57-26-no-uuid-here.jsonl"
content := `{"timestamp":"2026-04-27T02:57:26Z","type":"session_meta","payload":{"id":"` + wantID + `","cwd":"/tmp"}}` + "\n"
if err := os.WriteFile(filepath.Join(dir, fname), []byte(content), 0o644); err != nil {
t.Fatal(err)
}
r := <-ch
if r.err != nil {
t.Fatalf("unexpected error: %v", r.err)
}
if r.id != wantID {
t.Errorf("got id %q, want %q", r.id, wantID)
}
}
func TestWatchForNewCodexSession_TimeoutReturnsEmptyNil(t *testing.T) {
dir := t.TempDir()
ctx := context.Background()
id, err := WatchForNewCodexSession(ctx, CodexSessionWatchOpts{
SessionsDir: dir,
Timeout: 200 * time.Millisecond,
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if id != "" {
t.Errorf("expected empty string on timeout, got %q", id)
}
}
// TestWatchForNewCodexSession_FirstOfDay proves the primary fix: when
// SessionsDir does not exist at call time (first codex session of the day),
// MkdirAll creates it and the watcher still captures the rollout file.
func TestWatchForNewCodexSession_FirstOfDay(t *testing.T) {
base := t.TempDir()
// SessionsDir does NOT exist yet — simulates first-of-day scenario.
sessDir := filepath.Join(base, "2099", "12", "31")
ctx := context.Background()
ch := make(chan struct {
id string
err error
}, 1)
go func() {
id, err := WatchForNewCodexSession(ctx, CodexSessionWatchOpts{
SessionsDir: sessDir,
Timeout: 300 * time.Millisecond,
})
ch <- struct {
id string
err error
}{id, err}
}()
// Wait for watcher to start and MkdirAll to create the dir.
time.Sleep(50 * time.Millisecond)
uuid := "019dcb27-58a6-70a1-a5d1-bfc7f3ed9d0a"
fname := "rollout-2099-12-31T00-00-00-" + uuid + ".jsonl"
f, err := os.Create(filepath.Join(sessDir, fname))
if err != nil {
t.Fatalf("create rollout file: %v", err)
}
f.Close()
r := <-ch
if r.err != nil {
t.Fatalf("unexpected error: %v", r.err)
}
if r.id != uuid {
t.Errorf("got id %q, want %q (first-of-day session not captured)", r.id, uuid)
}
}
// TestWatchForNewCodexSession_MkdirAllFailReturnsEmptyNil verifies that when
// MkdirAll itself cannot create the dir (e.g. path under a file), the watcher
// returns ("", nil) without panicking.
func TestWatchForNewCodexSession_MkdirAllFailReturnsEmptyNil(t *testing.T) {
base := t.TempDir()
// Create a plain file so MkdirAll on a sub-path will fail.
blocker := filepath.Join(base, "blocker")
if err := os.WriteFile(blocker, []byte("x"), 0o644); err != nil {
t.Fatal(err)
}
ctx := context.Background()
id, err := WatchForNewCodexSession(ctx, CodexSessionWatchOpts{
SessionsDir: filepath.Join(blocker, "subdir"),
Timeout: 300 * time.Millisecond,
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if id != "" {
t.Errorf("expected empty string when MkdirAll fails, got %q", id)
}
}
func TestWatchForNewCodexSession_ContextCancel(t *testing.T) {
dir := t.TempDir()
ctx, cancel := context.WithCancel(context.Background())
ch := make(chan struct {
id string
err error
}, 1)
go func() {
id, err := WatchForNewCodexSession(ctx, CodexSessionWatchOpts{
SessionsDir: dir,
Timeout: 5 * time.Second,
})
ch <- struct {
id string
err error
}{id, err}
}()
time.Sleep(30 * time.Millisecond)
cancel()
r := <-ch
if r.err != nil {
t.Fatalf("unexpected error on cancel: %v", r.err)
}
if r.id != "" {
t.Errorf("expected empty id on cancel, got %q", r.id)
}
}