@@ -155,10 +155,12 @@ public void shouldPreferHttp3WhenRecentSuccessKeepsBaseDelay() throws Exception
155155 HTTP2JettyClient client = new HTTP2JettyClient (false , "IT-HTTP3-HE-Recent" );
156156 try {
157157 client .start ();
158- // Phase A: establish Alt-Svc and force one confirmed H3 success first.
158+ // Phase A: establish Alt-Svc and force one confirmed H3 success first. No protocol is
159+ // asserted on this first sample: first contact with an unknown origin explores HTTP/3, so
160+ // either side of the race may win it. The warmup loop below is what guarantees the
161+ // confirmed HTTP/3 success this test needs.
159162 HTTPSampleResult first = sample (client , sampler , url );
160163 assertThat (first .isSuccessful ()).isTrue ();
161- assertThat (first .getResponseHeaders ()).startsWith ("HTTP/2" );
162164
163165 h2DelayMs .set (500L );
164166 h3DelayMs .set (0L );
@@ -251,16 +253,42 @@ public void shouldSkipHttp3WhenMarkedBroken() throws Exception {
251253 HTTP2JettyClient client = new HTTP2JettyClient (false , "IT-HTTP3-HE-Broken" );
252254 try {
253255 client .start ();
254- HTTPSampleResult first = sample (client , sampler , url );
255- assertThat (first .isSuccessful ()).isTrue ();
256- assertThat (first .getResponseHeaders ()).startsWith ("HTTP/2" );
256+ // Setup, in two steps, so that the cooldown ends up being the only thing that can stop
257+ // HTTP/3 - otherwise this test passes without the cooldown doing any work.
258+ //
259+ // First, let HTTP/2 win a race so its Alt-Svc is recorded with h3=true. Marking an origin
260+ // broken when nothing is cached for it creates an entry saying h3=false, and that alone
261+ // stops HTTP/3 regardless of any cooldown.
262+ h3DelayMs .set (1000L );
263+ HTTPSampleResult altSvcLearn = sample (client , sampler , url );
264+ assertThat (altSvcLearn .isSuccessful ()).isTrue ();
265+ assertThat (altSvcLearn .getResponseHeaders ())
266+ .as ("HTTP/2 has to answer this one for its Alt-Svc to be cached" )
267+ .startsWith ("HTTP/2" );
268+ h3DelayMs .set (0L );
269+
270+ // Second, confirm HTTP/3 is actually being attempted now, so that its absence later means
271+ // something. No protocol is asserted on these samples: either side of the race may win.
272+ boolean http3Attempted = false ;
273+ for (int attempt = 0 ; attempt < 6 && !http3Attempted ; attempt ++) {
274+ int before = h3Requests .get ();
275+ HTTPSampleResult warmup = sample (client , sampler , url );
276+ assertThat (warmup .isSuccessful ()).isTrue ();
277+ http3Attempted = h3Requests .get () > before ;
278+ }
279+ assertThat (http3Attempted )
280+ .as ("the origin must be reaching HTTP/3 before the cooldown can be shown to stop it" )
281+ .isTrue ();
257282
258283 markHttp3Broken (client , url .toURI ());
284+ int h3RequestsWhenBroken = h3Requests .get ();
259285
260286 HTTPSampleResult second = sample (client , sampler , url );
261287 assertThat (second .isSuccessful ()).isTrue ();
262288 assertThat (second .getResponseHeaders ()).startsWith ("HTTP/2" );
263- assertThat (h3Requests .get ()).isEqualTo (0 );
289+ assertThat (h3Requests .get ())
290+ .as ("no HTTP/3 may be attempted once the origin is in the broken cooldown" )
291+ .isEqualTo (h3RequestsWhenBroken );
264292 } finally {
265293 client .stop ();
266294 }
0 commit comments