internal/http3: use go1.25 synctest.Test instead of go1.24 synctest.Run

internal/http3 was written back in go1.24, and relies on synctest.Run
and goexperiment.synctest. This prevents us from running tests with
newer versions of Go.

This CL updates the existing build constraint and synctest usages to
go1.25 so we can still run tests using go1.25 and tip. Support for
running synctest with go1.24 is not kept, since go1.26 release (and
therefore x/net go.mod updating to go1.25) is expected soon.

Change-Id: Iebfa82ebd1da4a06ba613ce0f45051f4691037fc
Reviewed-on: https://go-review.googlesource.com/c/net/+/734940
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Nicholas Husin <husin@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Nicholas S. Husin
2026-01-08 14:57:52 -05:00
committed by Nicholas Husin
parent 9ace223794
commit eea413e294
27 changed files with 47 additions and 134 deletions

View File

@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
package http3
import (

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24 && goexperiment.synctest
//go:build go1.25
package http3
@@ -256,7 +256,7 @@ func TestReadData(t *testing.T) {
}
runSynctestSubtest(t, test.name+"/client", func(t testing.TB) {
synctestSubtest(t, test.name+"/client", func(t *testing.T) {
tc := newTestClientConn(t)
tc.greet()

View File

@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
package http3
import (

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24 && goexperiment.synctest
//go:build go1.25
package http3
@@ -142,11 +142,11 @@ func TestConnPeerCreatesBadUnidirectionalStream(t *testing.T) {
func runConnTest(t *testing.T, f func(testing.TB, *testQUICConn)) {
t.Helper()
runSynctestSubtest(t, "client", func(t testing.TB) {
synctestSubtest(t, "client", func(t *testing.T) {
tc := newTestClientConn(t)
f(t, tc.testQUICConn)
})
runSynctestSubtest(t, "server", func(t testing.TB) {
synctestSubtest(t, "server", func(t *testing.T) {
ts := newTestServer(t)
tc := ts.connect()
f(t, tc.testQUICConn)

View File

@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
package http3
import "fmt"

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
//go:build go1.25
package http3
@@ -13,13 +13,11 @@ import (
"testing"
)
// TestFiles checks that every file in this package has a build constraint on Go 1.24.
// TestFiles checks that every test file in this package has a build constraint
// on Go 1.25. Tests rely on synctest.Test, added in Go 1.25.
//
// Package tests rely on testing/synctest, added as an experiment in Go 1.24.
// When moving internal/http3 to an importable location, we can decide whether
// to relax the constraint for non-test files.
//
// Drop this test when the x/net go.mod depends on 1.24 or newer.
// TODO(nsh): drop this test and Go 1.25 build contraints once x/net go.mod
// depends on 1.25 or newer.
func TestFiles(t *testing.T) {
f, err := os.Open(".")
if err != nil {
@@ -45,12 +43,10 @@ func TestFiles(t *testing.T) {
if name == "doc.go" {
continue
}
if !bytes.Contains(b, []byte("//go:build go1.24")) {
t.Errorf("%v: missing constraint on go1.24", name)
}
if bytes.Contains(b, []byte(`"testing/synctest"`)) &&
!bytes.Contains(b, []byte("//go:build go1.24 && goexperiment.synctest")) {
t.Errorf("%v: missing constraint on go1.24 && goexperiment.synctest", name)
if strings.HasSuffix(name, "_test.go") {
if !bytes.Contains(b, []byte("//go:build go1.25")) {
t.Errorf("%v: missing constraint on go1.25", name)
}
}
}
}

View File

@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
package http3
import "fmt"

View File

@@ -1,64 +0,0 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24 && goexperiment.synctest
package http3
import (
"context"
"slices"
"testing"
"testing/synctest"
)
// runSynctest runs f in a synctest.Run bubble.
// It arranges for t.Cleanup functions to run within the bubble.
// TODO: Replace with synctest.Test, which handles all this properly.
func runSynctest(t *testing.T, f func(t testing.TB)) {
synctest.Run(func() {
// Create a context within the bubble, rather than using t.Context.
ctx, cancel := context.WithCancel(context.Background())
ct := &cleanupT{
T: t,
ctx: ctx,
cancel: cancel,
}
defer ct.done()
f(ct)
})
}
// runSynctestSubtest runs f in a subtest in a synctest.Run bubble.
func runSynctestSubtest(t *testing.T, name string, f func(t testing.TB)) {
t.Run(name, func(t *testing.T) {
runSynctest(t, f)
})
}
// cleanupT wraps a testing.T and adds its own Cleanup method.
// Used to execute cleanup functions within a synctest bubble.
type cleanupT struct {
*testing.T
ctx context.Context
cancel context.CancelFunc
cleanups []func()
}
// Cleanup replaces T.Cleanup.
func (t *cleanupT) Cleanup(f func()) {
t.cleanups = append(t.cleanups, f)
}
// Context replaces T.Context.
func (t *cleanupT) Context() context.Context {
return t.ctx
}
func (t *cleanupT) done() {
t.cancel()
for _, f := range slices.Backward(t.cleanups) {
f()
}
}

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
//go:build go1.25
package http3
@@ -10,6 +10,8 @@ import (
"encoding/hex"
"os"
"strings"
"testing"
"testing/synctest"
)
func init() {
@@ -42,3 +44,10 @@ type testReader struct {
}
func (r testReader) Read(p []byte) (n int, err error) { return r.readFunc(p) }
// synctestSubtest runs f in a subtest in a synctest.Run bubble.
func synctestSubtest(t *testing.T, name string, f func(t *testing.T)) {
t.Run(name, func(t *testing.T) {
synctest.Test(t, f)
})
}

View File

@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
package http3
import (

View File

@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
package http3
import (

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24 && goexperiment.synctest
//go:build go1.25
package http3
@@ -102,7 +102,7 @@ func TestQPACKDecode(t *testing.T) {
{mayIndex, "accept-encoding", ""},
},
}} {
runSynctestSubtest(t, test.name, func(t testing.TB) {
synctestSubtest(t, test.name, func(t *testing.T) {
st1, st2 := newStreamPair(t)
st1.Write(test.enc)
st1.Flush()
@@ -176,7 +176,7 @@ func TestQPACKDecodeErrors(t *testing.T) {
name: "too high static table index",
enc: unhex("0000ff23ff24"),
}} {
runSynctestSubtest(t, test.name, func(t testing.TB) {
synctestSubtest(t, test.name, func(t *testing.T) {
st1, st2 := newStreamPair(t)
st1.Write(test.enc)
st1.Flush()

View File

@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
package http3
type qpackEncoder struct {

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
//go:build go1.25
package http3

View File

@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
package http3
import "sync"

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
//go:build go1.25
package http3

View File

@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
package http3
import (

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
//go:build go1.25
package http3

View File

@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
package http3
import (

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24 && goexperiment.synctest
//go:build go1.25
package http3
@@ -18,7 +18,7 @@ import (
)
func TestRoundTripSimple(t *testing.T) {
runSynctest(t, func(t testing.TB) {
synctest.Test(t, func(t *testing.T) {
tc := newTestClientConn(t)
tc.greet()
@@ -44,7 +44,7 @@ func TestRoundTripSimple(t *testing.T) {
}
func TestRoundTripWithBadHeaders(t *testing.T) {
runSynctest(t, func(t testing.TB) {
synctest.Test(t, func(t *testing.T) {
tc := newTestClientConn(t)
tc.greet()
@@ -56,7 +56,7 @@ func TestRoundTripWithBadHeaders(t *testing.T) {
}
func TestRoundTripWithUnknownFrame(t *testing.T) {
runSynctest(t, func(t testing.TB) {
synctest.Test(t, func(t *testing.T) {
tc := newTestClientConn(t)
tc.greet()
@@ -82,7 +82,7 @@ func TestRoundTripWithInvalidPushPromise(t *testing.T) {
// "A client MUST treat receipt of a PUSH_PROMISE frame that contains
// a larger push ID than the client has advertised as a connection error of H3_ID_ERROR."
// https://www.rfc-editor.org/rfc/rfc9114.html#section-7.2.5-5
runSynctest(t, func(t testing.TB) {
synctest.Test(t, func(t *testing.T) {
tc := newTestClientConn(t)
tc.greet()
@@ -155,7 +155,7 @@ func TestRoundTripResponseContentLength(t *testing.T) {
},
wantContentLength: -1,
}} {
runSynctestSubtest(t, test.name, func(t testing.TB) {
synctestSubtest(t, test.name, func(t *testing.T) {
tc := newTestClientConn(t)
tc.greet()
@@ -199,7 +199,7 @@ func TestRoundTripMalformedResponses(t *testing.T) {
name: "no :status",
respHeader: http.Header{},
}} {
runSynctestSubtest(t, test.name, func(t testing.TB) {
synctestSubtest(t, test.name, func(t *testing.T) {
tc := newTestClientConn(t)
tc.greet()
@@ -218,7 +218,7 @@ func TestRoundTripCrumbledCookiesInResponse(t *testing.T) {
// these MUST be concatenated into a single byte string [...]"
// using the two-byte delimiter of "; "''
// https://www.rfc-editor.org/rfc/rfc9114.html#section-4.2.1-2
runSynctest(t, func(t testing.TB) {
synctest.Test(t, func(t *testing.T) {
tc := newTestClientConn(t)
tc.greet()
@@ -238,7 +238,7 @@ func TestRoundTripCrumbledCookiesInResponse(t *testing.T) {
}
func TestRoundTripRequestBodySent(t *testing.T) {
runSynctest(t, func(t testing.TB) {
synctest.Test(t, func(t *testing.T) {
tc := newTestClientConn(t)
tc.greet()
@@ -290,7 +290,7 @@ func TestRoundTripRequestBodyErrors(t *testing.T) {
},
),
}} {
runSynctestSubtest(t, test.name, func(t testing.TB) {
synctestSubtest(t, test.name, func(t *testing.T) {
tc := newTestClientConn(t)
tc.greet()
@@ -323,7 +323,7 @@ func TestRoundTripRequestBodyErrors(t *testing.T) {
}
func TestRoundTripRequestBodyErrorAfterHeaders(t *testing.T) {
runSynctest(t, func(t testing.TB) {
synctest.Test(t, func(t *testing.T) {
tc := newTestClientConn(t)
tc.greet()

View File

@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
package http3
import (

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24 && goexperiment.synctest
//go:build go1.25
package http3
@@ -19,7 +19,7 @@ func TestServerReceivePushStream(t *testing.T) {
// "[...] if a server receives a client-initiated push stream,
// this MUST be treated as a connection error of type H3_STREAM_CREATION_ERROR."
// https://www.rfc-editor.org/rfc/rfc9114.html#section-6.2.2-3
runSynctest(t, func(t testing.TB) {
synctest.Test(t, func(t *testing.T) {
ts := newTestServer(t)
tc := ts.connect()
tc.newStream(streamTypePush)
@@ -28,7 +28,7 @@ func TestServerReceivePushStream(t *testing.T) {
}
func TestServerCancelPushForUnsentPromise(t *testing.T) {
runSynctest(t, func(t testing.TB) {
synctest.Test(t, func(t *testing.T) {
ts := newTestServer(t)
tc := ts.connect()
tc.greet()

View File

@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
package http3
import (

View File

@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
package http3
import (

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
//go:build go1.25
package http3

View File

@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
package http3
import (

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24 && goexperiment.synctest
//go:build go1.25
package http3
@@ -27,7 +27,7 @@ func TestTransportServerCreatesBidirectionalStream(t *testing.T) {
// "Clients MUST treat receipt of a server-initiated bidirectional
// stream as a connection error of type H3_STREAM_CREATION_ERROR [...]"
// https://www.rfc-editor.org/rfc/rfc9114.html#section-6.1-3
runSynctest(t, func(t testing.TB) {
synctest.Test(t, func(t *testing.T) {
tc := newTestClientConn(t)
tc.greet()
st := tc.newStream(streamTypeRequest)