]> git.feebdaed.xyz Git - 0xmirror/quic-go.git/commitdiff
avoid triggering macOS dual-stack flakiness in HTTP/3 integration tests (#5187)
authorMarten Seemann <martenseemann@gmail.com>
Sat, 31 May 2025 08:40:20 +0000 (16:40 +0800)
committerGitHub <noreply@github.com>
Sat, 31 May 2025 08:40:20 +0000 (10:40 +0200)
Unfortunately, there’s still no fix in sight for https://github.com/golang/go/issues/67226.

integrationtests/self/http_shutdown_test.go
integrationtests/self/http_test.go
integrationtests/self/http_trace_test.go
integrationtests/self/self_test.go

index 53cbbd8e06bc5a7f9b654c17715e00daceb374b5..ae5a8aeeb65f3183d09ab9ef014897922360af7f 100644 (file)
@@ -368,6 +368,7 @@ func testHTTP3ListenerClosing(t *testing.T, graceful, useApplicationListener boo
                tlsConf.NextProtos = []string{http3.NextProtoH3}
                tr := &http3.Transport{TLSClientConfig: tlsConf}
                defer tr.Close()
+               addDialCallback(t, tr)
                cl := &http.Client{Transport: tr}
                req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
                require.NoError(t, err)
@@ -396,7 +397,7 @@ func testHTTP3ListenerClosing(t *testing.T, graceful, useApplicationListener boo
                // the following values will be ignored when using ServeListener
                TLSConfig:  tlsConf,
                QUICConfig: getQuicConfig(nil),
-               Addr:       "127.0.0.1:47283",
+               Addr:       "127.0.0.1:0",
        }
 
        serveChan := make(chan error, 1)
@@ -411,7 +412,17 @@ func testHTTP3ListenerClosing(t *testing.T, graceful, useApplicationListener boo
                go func() { serveChan <- server.ServeListener(ln) }()
        } else {
                go func() { serveChan <- server.ListenAndServe() }()
-               host = server.Addr
+               // The server is listening on a random port, and the only way to get the port
+               // is to parse the Alt-Svc header.
+               var port int
+               require.Eventually(t, func() bool {
+                       hdr := make(http.Header)
+                       server.SetQUICHeaders(hdr)
+                       altSvc := hdr.Get("Alt-Svc")
+                       n, err := fmt.Sscanf(altSvc, `h3=":%d"`, &port)
+                       return err == nil && n == 1
+               }, time.Second, 10*time.Millisecond)
+               host = fmt.Sprintf("127.0.0.1:%d", port)
        }
 
        u := &url.URL{Scheme: "https", Host: host, Path: "/ok"}
@@ -471,10 +482,7 @@ func testHTTP3ListenerClosing(t *testing.T, graceful, useApplicationListener boo
                for range 2 {
                        ctx, cancel := context.WithTimeout(context.Background(), time.Second)
                        defer cancel()
-                       err := dial(t, ctx, u)
-                       var h3Err *http3.Error
-                       require.ErrorAs(t, err, &h3Err)
-                       require.Equal(t, http3.ErrCode(1337), h3Err.ErrorCode)
+                       require.ErrorIs(t, dial(t, ctx, u), &http3.Error{ErrorCode: 1337, Remote: true})
                        select {
                        case err := <-errChan:
                                require.NoError(t, err)
index 6e81165b088e2ec4d356654db3e6f1cbc959676e..8f496523aa90abf0fc9ce7ee96974f844656f33c 100644 (file)
@@ -85,6 +85,7 @@ func newHTTP3Client(t *testing.T) *http.Client {
                QUICConfig:         getQuicConfig(&quic.Config{MaxIdleTimeout: 10 * time.Second}),
                DisableCompression: true,
        }
+       addDialCallback(t, tr)
        t.Cleanup(func() { tr.Close() })
        return &http.Client{Transport: tr}
 }
@@ -356,7 +357,13 @@ func TestHTTPDifferentOrigins(t *testing.T) {
        })
        port := startHTTPServer(t, mux)
 
-       cl := newHTTP3Client(t)
+       tr := &http3.Transport{
+               TLSClientConfig: getTLSClientConfigWithoutServerName(),
+               QUICConfig:      getQuicConfig(nil),
+       }
+       t.Cleanup(func() { tr.Close() })
+       cl := &http.Client{Transport: tr}
+
        resp, err := cl.Get(fmt.Sprintf("https://localhost:%d/remote-addr", port))
        require.NoError(t, err)
        require.Equal(t, http.StatusOK, resp.StatusCode)
@@ -888,6 +895,7 @@ func TestHTTP0RTT(t *testing.T) {
                DisableCompression: true,
        }
        defer tr.Close()
+       addDialCallback(t, tr)
 
        proxyPort := proxy.LocalAddr().(*net.UDPAddr).Port
        req, err := http.NewRequest(http3.MethodGet0RTT, fmt.Sprintf("https://localhost:%d/0rtt", proxyPort), nil)
@@ -912,6 +920,7 @@ func TestHTTP0RTT(t *testing.T) {
                DisableCompression: true,
        }
        defer tr2.Close()
+       addDialCallback(t, tr2)
        rsp, err = tr2.RoundTrip(req)
        require.NoError(t, err)
        require.Equal(t, 200, rsp.StatusCode)
@@ -949,6 +958,7 @@ func TestHTTPStreamer(t *testing.T) {
        require.NoError(t, err)
        defer conn.CloseWithError(0, "")
        tr := http3.Transport{}
+       addDialCallback(t, &tr)
        cc := tr.NewClientConn(conn)
        str, err := cc.OpenRequestStream(ctx)
        require.NoError(t, err)
index f894495fdf917e4de6d73f1ba6be5fa728cc886d..aa1baaac4afe14fbdbfc789f29791cbdf0f3de4f 100644 (file)
@@ -11,6 +11,7 @@ import (
        "testing"
        "time"
 
+       "github.com/quic-go/quic-go/http3"
        "github.com/stretchr/testify/require"
 )
 
@@ -62,7 +63,13 @@ func TestHTTPClientTrace(t *testing.T) {
        }
        ctx := httptrace.WithClientTrace(context.Background(), &trace)
 
-       cl := newHTTP3Client(t)
+       tr := &http3.Transport{
+               TLSClientConfig: getTLSClientConfigWithoutServerName(),
+               QUICConfig:      getQuicConfig(nil),
+       }
+       t.Cleanup(func() { tr.Close() })
+       cl := &http.Client{Transport: tr}
+
        req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("https://localhost:%d/client-trace", port), nil)
        require.NoError(t, err)
        resp, err := cl.Do(req)
index 6df7863b67933f3bfd183e33e03a6be1f996d4cf..4a9e8a4cf2fbb43d5d132eef43ca4e7e0fe375e0 100644 (file)
@@ -10,11 +10,13 @@ import (
        "math/rand/v2"
        "net"
        "os"
+       "runtime"
        "strconv"
        "testing"
        "time"
 
        "github.com/quic-go/quic-go"
+       "github.com/quic-go/quic-go/http3"
        "github.com/quic-go/quic-go/integrationtests/tools"
        "github.com/quic-go/quic-go/internal/protocol"
        "github.com/quic-go/quic-go/internal/wire"
@@ -298,3 +300,23 @@ func contains0RTTPacket(data []byte) bool {
        }
        return false
 }
+
+// addDialCallback explicitly adds the http3.Transport's Dial callback.
+// This is needed since dialing on dual-stack sockets is flaky on macOS,
+// see https://github.com/golang/go/issues/67226.
+func addDialCallback(t *testing.T, tr *http3.Transport) {
+       t.Helper()
+
+       if runtime.GOOS != "darwin" {
+               return
+       }
+
+       require.Nil(t, tr.Dial)
+       tr.Dial = func(ctx context.Context, addr string, tlsConf *tls.Config, conf *quic.Config) (quic.EarlyConnection, error) {
+               a, err := net.ResolveUDPAddr("udp", addr)
+               if err != nil {
+                       return nil, err
+               }
+               return quic.DialEarly(ctx, newUDPConnLocalhost(t), a, tlsConf, conf)
+       }
+}