//go:build linux || darwin package diagnostics import ( "io" "os" "path/filepath" "syscall" "testing" ) func TestTranscriptStreamDestinations(t *testing.T) { fifo := filepath.Join(t.TempDir(), "transcript.pipe") if err := syscall.Mkfifo(fifo, 0600); err != nil { t.Fatal(err) } for _, path := range []string{os.DevNull, fifo} { t.Run(filepath.Base(path), func(t *testing.T) { before, err := os.Stat(path) if err != nil { t.Fatal(err) } // Preparation must finish even though the pipe has no reader yet. session, err := PrepareOutput(OutputSelection{TranscriptPath: path}) if err != nil { t.Fatal(err) } var reader *os.File if path == fifo { // Keep both ends open in the test so publication and reading can be // sequential; the small payload fits in the pipe buffer. reader, err = os.OpenFile(path, os.O_RDWR|syscall.O_NONBLOCK, 0) if err != nil { t.Fatal(err) } defer reader.Close() } payload := []byte("transcript") if failures := session.Finalize(payload, ReportBundle{}, nil); len(failures) != 0 { t.Fatal(failures) } after, err := os.Stat(path) if err != nil || !os.SameFile(before, after) || before.Mode() != after.Mode() { t.Fatalf("stream replaced: %v", err) } if reader != nil { got := make([]byte, len(payload)) if _, err := io.ReadFull(reader, got); err != nil || string(got) != string(payload) { t.Fatalf("pipe delivery: %q %v", got, err) } } }) } } func TestTranscriptStreamWriteFailure(t *testing.T) { if _, err := os.Stat("/dev/full"); os.IsNotExist(err) { t.Skip("/dev/full unavailable") } session, err := PrepareOutput(OutputSelection{TranscriptPath: "/dev/full"}) if err != nil { t.Fatal(err) } failures := session.Finalize([]byte("transcript"), ReportBundle{}, nil) if len(failures) != 1 || failures[0].Kind != "transcript write" { t.Fatalf("write failure lost: %+v", failures) } }