Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbd92df20f |
@@ -187,7 +187,74 @@ func TestWebhookHandlerTimesOutOnServerThatNeverAnswers(t *testing.T) {
|
|||||||
t.Fatalf("NewWebhookHandler: %v", err)
|
t.Fatalf("NewWebhookHandler: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = handler.Handle(context.Background(), errorTestRecord())
|
// Handle runs in a goroutine so that a lost timeout fails the test
|
||||||
|
// instead of hanging the test run.
|
||||||
|
handleErr := make(chan error, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
handleErr <- handler.Handle(context.Background(), errorTestRecord())
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err = <-handleErr:
|
||||||
|
case <-time.After(webhookTimeout + time.Second):
|
||||||
|
t.Fatal("Handle did not return within webhookTimeout")
|
||||||
|
}
|
||||||
|
|
||||||
|
var netErr net.Error
|
||||||
|
if !errors.As(err, &netErr) || !netErr.Timeout() {
|
||||||
|
t.Fatalf("Handle returned %v, want a timeout error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A server that sends a 2xx status and then never finishes the answer
|
||||||
|
// must not hold up the log call either: reading the answer counts toward
|
||||||
|
// webhookTimeout, and Handle returns the read's error.
|
||||||
|
func TestWebhookHandlerTimesOutOnServerThatStallsTheAnswer(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
testEnded := make(chan struct{})
|
||||||
|
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(
|
||||||
|
func(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
// Flush sends the status now; the answer stays unfinished
|
||||||
|
// until the test ends.
|
||||||
|
err := http.NewResponseController(w).Flush()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("flush the status: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
<-testEnded
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
// server.Close waits for running requests, so the server's handler
|
||||||
|
// is released first.
|
||||||
|
defer func() {
|
||||||
|
close(testEnded)
|
||||||
|
server.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
handler, err := NewWebhookHandler(server.URL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewWebhookHandler: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle runs in a goroutine so that a lost timeout fails the test
|
||||||
|
// instead of hanging the test run.
|
||||||
|
handleErr := make(chan error, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
handleErr <- handler.Handle(context.Background(), errorTestRecord())
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err = <-handleErr:
|
||||||
|
case <-time.After(webhookTimeout + time.Second):
|
||||||
|
t.Fatal("Handle did not return within webhookTimeout")
|
||||||
|
}
|
||||||
|
|
||||||
var netErr net.Error
|
var netErr net.Error
|
||||||
if !errors.As(err, &netErr) || !netErr.Timeout() {
|
if !errors.As(err, &netErr) || !netErr.Timeout() {
|
||||||
|
|||||||
+10
-6
@@ -113,12 +113,16 @@ func (w *WebhookHandler) Handle(ctx context.Context, record slog.Record) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// The answer is read to the end before closing, so the client can
|
defer func() { _ = response.Body.Close() }()
|
||||||
// reuse the connection for the next record.
|
|
||||||
defer func() {
|
// The answer is read to the end so the client can reuse the
|
||||||
_, _ = io.Copy(io.Discard, response.Body)
|
// connection for the next record. The read counts toward
|
||||||
_ = response.Body.Close()
|
// webhookTimeout, so a server that sends its status and then stalls
|
||||||
}()
|
// fails here.
|
||||||
|
_, err = io.Copy(io.Discard, response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if response.StatusCode < http.StatusOK ||
|
if response.StatusCode < http.StatusOK ||
|
||||||
response.StatusCode >= http.StatusMultipleChoices {
|
response.StatusCode >= http.StatusMultipleChoices {
|
||||||
|
|||||||
Reference in New Issue
Block a user