test: synchronize log capture with asynchronous HTTP logging
This commit is contained in:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user