test: synchronize log capture with asynchronous HTTP logging

This commit is contained in:
2026-10-10 11:42:26 +08:00
parent 60fe840662
commit 7357eae7cf
+61 -2
View File
@@ -7,18 +7,77 @@ import (
"log"
"log/slog"
"strings"
"sync"
"testing"
)
func installTestLogger(t *testing.T, debug bool) *bytes.Buffer {
// HTTP transports can finish logging request bodies asynchronously. Every
// writer and snapshot reader must synchronize on the same capture lock.
// Bytes returns a copy so callers cannot mutate the buffer after unlocking.
type testLogCapture struct {
mu sync.Mutex
buffer bytes.Buffer
}
func (b *testLogCapture) Write(p []byte) (int, error) {
b.mu.Lock()
defer b.mu.Unlock()
return b.buffer.Write(p)
}
func (b *testLogCapture) String() string {
b.mu.Lock()
defer b.mu.Unlock()
return b.buffer.String()
}
func (b *testLogCapture) Bytes() []byte {
b.mu.Lock()
defer b.mu.Unlock()
return bytes.Clone(b.buffer.Bytes())
}
func installTestLogger(t *testing.T, debug bool) *testLogCapture {
t.Helper()
previous := slog.Default()
out := new(bytes.Buffer)
out := new(testLogCapture)
Configure("dispatcher", debug, out)
t.Cleanup(func() { slog.SetDefault(previous) })
return out
}
func TestLogCaptureConcurrentSnapshots(t *testing.T) {
out := installTestLogger(t, false)
started := make(chan struct{})
done := make(chan error, 1)
go func() {
close(started)
for i := 0; i < 1000; i++ {
if _, err := out.Write([]byte("record\n")); err != nil {
done <- err
return
}
}
done <- nil
}()
<-started
for i := 0; i < 1000; i++ {
_ = out.String()
_ = out.Bytes()
}
if err := <-done; err != nil {
t.Fatal(err)
}
if count := strings.Count(out.String(), "record\n"); count != 1000 {
t.Fatalf("captured %d records, want 1000", count)
}
copyOfCapture := out.Bytes()
copyOfCapture[0] = 'X'
if strings.HasPrefix(out.String(), "X") {
t.Fatal("snapshot exposes the live capture buffer")
}
}
func TestLogrusModesIncludeWorkflowButOnlyDebugIncludesBody(t *testing.T) {
for _, debug := range []bool{false, true} {
t.Run(map[bool]string{false: "normal", true: "debug"}[debug], func(t *testing.T) {