forked from quic-go/quic-go
128 lines
3.6 KiB
Go
128 lines
3.6 KiB
Go
package self_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/quic-go/quic-go/http3"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestHTTPShutdown(t *testing.T) {
|
|
mux := http.NewServeMux()
|
|
var server *http3.Server
|
|
port := startHTTPServer(t, mux, func(s *http3.Server) { server = s })
|
|
client := newHTTP3Client(t)
|
|
|
|
mux.HandleFunc("/shutdown", func(w http.ResponseWriter, r *http.Request) {
|
|
go func() {
|
|
require.NoError(t, server.Close())
|
|
}()
|
|
time.Sleep(50 * time.Millisecond) // make sure the server started shutting down
|
|
})
|
|
|
|
_, err := client.Get(fmt.Sprintf("https://localhost:%d/shutdown", port))
|
|
require.Error(t, err)
|
|
var appErr *http3.Error
|
|
require.ErrorAs(t, err, &appErr)
|
|
require.Equal(t, http3.ErrCodeNoError, appErr.ErrorCode)
|
|
}
|
|
|
|
func TestGracefulShutdownShortRequest(t *testing.T) {
|
|
delay := scaleDuration(50 * time.Millisecond)
|
|
|
|
var server *http3.Server
|
|
mux := http.NewServeMux()
|
|
port := startHTTPServer(t, mux, func(s *http3.Server) { server = s })
|
|
errChan := make(chan error, 1)
|
|
mux.HandleFunc("/shutdown", func(w http.ResponseWriter, r *http.Request) {
|
|
go func() {
|
|
defer close(errChan)
|
|
errChan <- server.Shutdown(context.Background())
|
|
}()
|
|
time.Sleep(delay)
|
|
w.Write([]byte("shutdown"))
|
|
})
|
|
|
|
client := newHTTP3Client(t)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 3*delay)
|
|
defer cancel()
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("https://localhost:%d/shutdown", port), nil)
|
|
require.NoError(t, err)
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
require.Equal(t, []byte("shutdown"), body)
|
|
client.Transport.(*http3.Transport).Close() // manually close the client
|
|
|
|
select {
|
|
case err := <-errChan:
|
|
require.NoError(t, err)
|
|
case <-time.After(time.Second):
|
|
t.Fatal("shutdown did not complete")
|
|
}
|
|
}
|
|
|
|
func TestGracefulShutdownLongLivedRequest(t *testing.T) {
|
|
delay := scaleDuration(50 * time.Millisecond)
|
|
errChan := make(chan error, 1)
|
|
requestChan := make(chan time.Duration, 1)
|
|
|
|
var server *http3.Server
|
|
mux := http.NewServeMux()
|
|
port := startHTTPServer(t, mux, func(s *http3.Server) { server = s })
|
|
mux.HandleFunc("/shutdown", func(w http.ResponseWriter, r *http.Request) {
|
|
start := time.Now()
|
|
w.WriteHeader(http.StatusOK)
|
|
w.(http.Flusher).Flush()
|
|
|
|
go func() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), delay)
|
|
defer cancel()
|
|
errChan <- server.Shutdown(ctx)
|
|
}()
|
|
|
|
// measure how long it takes until the request errors
|
|
for t := range time.NewTicker(delay / 10).C {
|
|
if _, err := w.Write([]byte(t.String())); err != nil {
|
|
requestChan <- time.Since(start)
|
|
return
|
|
}
|
|
}
|
|
})
|
|
|
|
start := time.Now()
|
|
resp, err := newHTTP3Client(t).Get(fmt.Sprintf("https://localhost:%d/shutdown", port))
|
|
require.NoError(t, err)
|
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
|
_, err = io.Copy(io.Discard, resp.Body)
|
|
require.Error(t, err)
|
|
var h3Err *http3.Error
|
|
require.ErrorAs(t, err, &h3Err)
|
|
require.Equal(t, http3.ErrCodeNoError, h3Err.ErrorCode)
|
|
took := time.Since(start)
|
|
require.InDelta(t, delay.Seconds(), took.Seconds(), (delay / 2).Seconds())
|
|
|
|
// make sure that shutdown returned due to context deadline
|
|
select {
|
|
case err := <-errChan:
|
|
require.ErrorIs(t, err, context.DeadlineExceeded)
|
|
case <-time.After(time.Second):
|
|
t.Fatal("shutdown did not return due to context deadline")
|
|
}
|
|
|
|
select {
|
|
case requestDuration := <-requestChan:
|
|
require.InDelta(t, delay.Seconds(), requestDuration.Seconds(), (delay / 2).Seconds())
|
|
case <-time.After(time.Second):
|
|
t.Fatal("did not receive request duration")
|
|
}
|
|
}
|