package spill import ( "os" "path/filepath" "strings" "testing" "time" ) func TestSaveAndReuse(t *testing.T) { dir := t.TempDir() path, err := Save(dir, "call_abc-123", "hello world") if err != nil { t.Fatal(err) } if filepath.Dir(path) != dir { t.Errorf("unexpected dir: %s", path) } got, err := os.ReadFile(path) if err != nil { t.Fatal(err) } if string(got) != "hello world" { t.Errorf("content = %q", got) } // 幂等:同 callID 再存一次,路径相同且目录只多出 1 个文件。 path2, err := Save(dir, "call_abc-123", "hello world") if err != nil { t.Fatal(err) } if path2 != path { t.Errorf("path changed on reuse: %s vs %s", path, path2) } entries, _ := os.ReadDir(dir) if len(entries) != 1 { t.Errorf("want 1 file, got %d", len(entries)) } } func TestSaveSanitizesCallID(t *testing.T) { dir := t.TempDir() path, err := Save(dir, "../../etc/passwd", "x") if err != nil { t.Fatal(err) } // 必须落在 dir 内(无路径穿越)。 if filepath.Dir(path) != dir { t.Fatalf("path escaped dir: %s", path) } name := filepath.Base(path) if strings.ContainsAny(name, "/\\") || strings.Contains(name, "..") { t.Errorf("unsafe filename: %q", name) } } func TestSaveHashFallbackAndEmptyDir(t *testing.T) { dir := t.TempDir() path, err := Save(dir, "", strings.Repeat("z", 10)) if err != nil { t.Fatal(err) } if !strings.HasPrefix(filepath.Base(path), "sha-") { t.Errorf("empty callID should fall back to hash name, got %q", filepath.Base(path)) } if _, err := Save("", "id", "x"); err == nil { t.Error("empty dir must error") } } func TestPruneRemovesOldFiles(t *testing.T) { dir := t.TempDir() old := filepath.Join(dir, "old.txt") if err := os.WriteFile(old, []byte("x"), 0o644); err != nil { t.Fatal(err) } // 把 mtime 拨到 8 天前。 past := time.Now().Add(-8 * 24 * time.Hour) if err := os.Chtimes(old, past, past); err != nil { t.Fatal(err) } fresh := filepath.Join(dir, "fresh.txt") if err := os.WriteFile(fresh, []byte("y"), 0o644); err != nil { t.Fatal(err) } Prune(dir) if _, err := os.Stat(old); !os.IsNotExist(err) { t.Error("old file should have been pruned") } if _, err := os.Stat(fresh); err != nil { t.Error("fresh file should survive") } // 目录不存在时不应 panic。 Prune(filepath.Join(dir, "nope")) }