Make prompt debug creation concurrency safe
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
package promptdebug
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -91,6 +93,73 @@ func TestPromptDebugWriterAtomicallyReplacesArtifacts(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPromptDebugWriterCreatesSharedMissingAncestorsConcurrently(t *testing.T) {
|
||||
root := filepath.Join(t.TempDir(), "debug")
|
||||
writer, err := NewPromptDebugWriter(root)
|
||||
if err != nil {
|
||||
t.Fatalf("NewPromptDebugWriter() error = %v", err)
|
||||
}
|
||||
|
||||
const writerCount = 8
|
||||
start := make(chan struct{})
|
||||
type writeResult struct {
|
||||
directory string
|
||||
err error
|
||||
}
|
||||
results := make(chan writeResult, writerCount)
|
||||
var writers sync.WaitGroup
|
||||
for index := 0; index < writerCount; index++ {
|
||||
writers.Add(1)
|
||||
go func(index int) {
|
||||
defer writers.Done()
|
||||
<-start
|
||||
directory, err := writer.WritePreparation(PromptDebugRef{
|
||||
ReportID: report.Daily, ValidDate: "2026-05-29", RunID: fmt.Sprintf("run-%02d", index),
|
||||
}, promptDebugPreparationFixture(), nil)
|
||||
results <- writeResult{directory: directory, err: err}
|
||||
}(index)
|
||||
}
|
||||
close(start)
|
||||
|
||||
finished := make(chan struct{})
|
||||
go func() {
|
||||
writers.Wait()
|
||||
close(finished)
|
||||
}()
|
||||
select {
|
||||
case <-finished:
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("concurrent prompt debug writes did not finish")
|
||||
}
|
||||
close(results)
|
||||
|
||||
directories := map[string]struct{}{}
|
||||
for result := range results {
|
||||
if result.err != nil {
|
||||
t.Fatalf("WritePreparation() error = %v", result.err)
|
||||
}
|
||||
if _, duplicate := directories[result.directory]; duplicate {
|
||||
t.Fatalf("duplicate debug directory %q", result.directory)
|
||||
}
|
||||
directories[result.directory] = struct{}{}
|
||||
if _, err := os.Stat(filepath.Join(result.directory, "preparation.json")); err != nil {
|
||||
t.Fatalf("preparation artifact %q: %v", result.directory, err)
|
||||
}
|
||||
}
|
||||
if len(directories) != writerCount {
|
||||
t.Fatalf("debug directories = %#v", directories)
|
||||
}
|
||||
if runtime.GOOS != "windows" {
|
||||
assertPromptDebugMode(t, root, debugDirectoryMode)
|
||||
assertPromptDebugMode(t, filepath.Join(root, "daily"), debugDirectoryMode)
|
||||
assertPromptDebugMode(t, filepath.Join(root, "daily", "2026-05-29"), debugDirectoryMode)
|
||||
for directory := range directories {
|
||||
assertPromptDebugMode(t, directory, debugDirectoryMode)
|
||||
assertPromptDebugMode(t, filepath.Join(directory, "preparation.json"), debugFileMode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPromptDebugWriterDisabledDoesNotAccessFilesystem(t *testing.T) {
|
||||
writer, err := NewPromptDebugWriter("")
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user