diff --git a/internal/http3/body.go b/internal/http3/body.go index cdde482e..868f85c4 100644 --- a/internal/http3/body.go +++ b/internal/http3/body.go @@ -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 ( diff --git a/internal/http3/body_test.go b/internal/http3/body_test.go index 599e0df8..c2288d3d 100644 --- a/internal/http3/body_test.go +++ b/internal/http3/body_test.go @@ -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() diff --git a/internal/http3/conn.go b/internal/http3/conn.go index 5eb80311..6a3c962b 100644 --- a/internal/http3/conn.go +++ b/internal/http3/conn.go @@ -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 ( diff --git a/internal/http3/conn_test.go b/internal/http3/conn_test.go index a9afb1f9..78f19c46 100644 --- a/internal/http3/conn_test.go +++ b/internal/http3/conn_test.go @@ -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) diff --git a/internal/http3/errors.go b/internal/http3/errors.go index db46acfc..273ad014 100644 --- a/internal/http3/errors.go +++ b/internal/http3/errors.go @@ -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" diff --git a/internal/http3/files_test.go b/internal/http3/files_test.go index 9c97a6ce..fcb4596d 100644 --- a/internal/http3/files_test.go +++ b/internal/http3/files_test.go @@ -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) + } } } } diff --git a/internal/http3/http3.go b/internal/http3/http3.go index 1f606705..edbba0ca 100644 --- a/internal/http3/http3.go +++ b/internal/http3/http3.go @@ -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" diff --git a/internal/http3/http3_synctest_test.go b/internal/http3/http3_synctest_test.go deleted file mode 100644 index a9c0ac29..00000000 --- a/internal/http3/http3_synctest_test.go +++ /dev/null @@ -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() - } -} diff --git a/internal/http3/http3_test.go b/internal/http3/http3_test.go index f6fb2e9b..ef6bd027 100644 --- a/internal/http3/http3_test.go +++ b/internal/http3/http3_test.go @@ -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) + }) +} diff --git a/internal/http3/qpack.go b/internal/http3/qpack.go index 8fb4860b..64ce99aa 100644 --- a/internal/http3/qpack.go +++ b/internal/http3/qpack.go @@ -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 ( diff --git a/internal/http3/qpack_decode.go b/internal/http3/qpack_decode.go index 018867af..7348ae76 100644 --- a/internal/http3/qpack_decode.go +++ b/internal/http3/qpack_decode.go @@ -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 ( diff --git a/internal/http3/qpack_decode_test.go b/internal/http3/qpack_decode_test.go index 3b9a995f..d812d6dd 100644 --- a/internal/http3/qpack_decode_test.go +++ b/internal/http3/qpack_decode_test.go @@ -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() diff --git a/internal/http3/qpack_encode.go b/internal/http3/qpack_encode.go index 0f35e0c5..193f7f93 100644 --- a/internal/http3/qpack_encode.go +++ b/internal/http3/qpack_encode.go @@ -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 { diff --git a/internal/http3/qpack_encode_test.go b/internal/http3/qpack_encode_test.go index f426d773..f642821d 100644 --- a/internal/http3/qpack_encode_test.go +++ b/internal/http3/qpack_encode_test.go @@ -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 diff --git a/internal/http3/qpack_static.go b/internal/http3/qpack_static.go index cb0884eb..6c0b51c5 100644 --- a/internal/http3/qpack_static.go +++ b/internal/http3/qpack_static.go @@ -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" diff --git a/internal/http3/qpack_test.go b/internal/http3/qpack_test.go index 6e16511f..29473bf2 100644 --- a/internal/http3/qpack_test.go +++ b/internal/http3/qpack_test.go @@ -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 diff --git a/internal/http3/quic.go b/internal/http3/quic.go index 6d2b1200..4f1cca17 100644 --- a/internal/http3/quic.go +++ b/internal/http3/quic.go @@ -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 ( diff --git a/internal/http3/quic_test.go b/internal/http3/quic_test.go index bc3b110f..f494811b 100644 --- a/internal/http3/quic_test.go +++ b/internal/http3/quic_test.go @@ -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 diff --git a/internal/http3/roundtrip.go b/internal/http3/roundtrip.go index bf55a131..d52c8455 100644 --- a/internal/http3/roundtrip.go +++ b/internal/http3/roundtrip.go @@ -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 ( diff --git a/internal/http3/roundtrip_test.go b/internal/http3/roundtrip_test.go index ba6a234a..230ff82c 100644 --- a/internal/http3/roundtrip_test.go +++ b/internal/http3/roundtrip_test.go @@ -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() diff --git a/internal/http3/server.go b/internal/http3/server.go index ca93c529..bdb3479b 100644 --- a/internal/http3/server.go +++ b/internal/http3/server.go @@ -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 ( diff --git a/internal/http3/server_test.go b/internal/http3/server_test.go index 8e727d25..1e0cba95 100644 --- a/internal/http3/server_test.go +++ b/internal/http3/server_test.go @@ -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() diff --git a/internal/http3/settings.go b/internal/http3/settings.go index b5e562ec..b3cb2a64 100644 --- a/internal/http3/settings.go +++ b/internal/http3/settings.go @@ -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 ( diff --git a/internal/http3/stream.go b/internal/http3/stream.go index 345e2f50..93294d43 100644 --- a/internal/http3/stream.go +++ b/internal/http3/stream.go @@ -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 ( diff --git a/internal/http3/stream_test.go b/internal/http3/stream_test.go index a034cc76..036b2356 100644 --- a/internal/http3/stream_test.go +++ b/internal/http3/stream_test.go @@ -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 diff --git a/internal/http3/transport.go b/internal/http3/transport.go index b26524cb..48aaadd8 100644 --- a/internal/http3/transport.go +++ b/internal/http3/transport.go @@ -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 ( diff --git a/internal/http3/transport_test.go b/internal/http3/transport_test.go index b3008663..0b7134ad 100644 --- a/internal/http3/transport_test.go +++ b/internal/http3/transport_test.go @@ -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)