Skip to content

Commit 7a49588

Browse files
Fix flaky Http2 Trailers tests (#60483)
1 parent 5f65ff3 commit 7a49588

File tree

1 file changed

+23
-3
lines changed

1 file changed

+23
-3
lines changed

src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2StreamTests.cs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5239,10 +5239,10 @@ await InitializeConnectionAsync(async context =>
52395239

52405240
await context.Response.CompleteAsync().DefaultTimeout();
52415241

5242-
Assert.True(context.Features.Get<IHttpResponseTrailersFeature>().Trailers.IsReadOnly);
5243-
52445242
// Make sure the client gets our results from CompleteAsync instead of from the request delegate exiting.
52455243
await clientTcs.Task.DefaultTimeout();
5244+
5245+
Assert.True(context.Features.Get<IHttpResponseTrailersFeature>().Trailers.IsReadOnly);
52465246
appTcs.SetResult();
52475247
}
52485248
catch (Exception ex)
@@ -5432,6 +5432,7 @@ await WaitForStreamErrorAsync(1, Http2ErrorCode.INTERNAL_ERROR,
54325432
public async Task AbortAfterCompleteAsync_GETWithResponseBodyAndTrailers_ResetsAfterResponse()
54335433
{
54345434
var startingTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
5435+
var trailersTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
54355436
var appTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
54365437
var clientTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
54375438
var headers = new[]
@@ -5453,6 +5454,9 @@ await InitializeConnectionAsync(async context =>
54535454
context.Response.AppendTrailer("CustomName", "Custom Value");
54545455

54555456
await context.Response.CompleteAsync().DefaultTimeout();
5457+
// Http2FrameWriter sets Trailers.IsReadOnly to true, but since it's a background task we have to wait for something to indicate it ran
5458+
// That something is the client side receiving the trailers.
5459+
await trailersTcs.Task;
54565460

54575461
Assert.True(context.Features.Get<IHttpResponseTrailersFeature>().Trailers.IsReadOnly);
54585462

@@ -5484,6 +5488,7 @@ await InitializeConnectionAsync(async context =>
54845488
withLength: 25,
54855489
withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM),
54865490
withStreamId: 1);
5491+
trailersTcs.SetResult();
54875492
// Stream should return an INTERNAL_ERROR. If there is an unexpected exception from app TCS instead, then throw it here to avoid timeout waiting for the stream error.
54885493
await Task.WhenAny(WaitForStreamErrorAsync(1, Http2ErrorCode.INTERNAL_ERROR, expectedErrorMessage: null), appTcs.Task).Unwrap();
54895494

@@ -5512,6 +5517,7 @@ await InitializeConnectionAsync(async context =>
55125517
public async Task AbortAfterCompleteAsync_POSTWithResponseBodyAndTrailers_RequestBodyThrows()
55135518
{
55145519
var startingTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
5520+
var trailersTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
55155521
var appTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
55165522
var clientTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
55175523
var headers = new[]
@@ -5535,7 +5541,10 @@ await InitializeConnectionAsync(async context =>
55355541
context.Response.AppendTrailer("CustomName", "Custom Value");
55365542

55375543
await context.Response.CompleteAsync().DefaultTimeout();
5538-
5544+
// Http2FrameWriter sets Trailers.IsReadOnly to true, but since it's a background task we have to wait for something to indicate it ran
5545+
// That something is the client side receiving the trailers.
5546+
await trailersTcs.Task;
5547+
55395548
Assert.True(context.Features.Get<IHttpResponseTrailersFeature>().Trailers.IsReadOnly);
55405549

55415550
// RequestAborted will no longer fire after CompleteAsync.
@@ -5569,6 +5578,7 @@ await InitializeConnectionAsync(async context =>
55695578
withLength: 25,
55705579
withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM),
55715580
withStreamId: 1);
5581+
trailersTcs.SetResult();
55725582
await WaitForStreamErrorAsync(1, Http2ErrorCode.INTERNAL_ERROR, expectedErrorMessage: null);
55735583

55745584
clientTcs.SetResult();
@@ -5596,6 +5606,7 @@ await InitializeConnectionAsync(async context =>
55965606
public async Task ResetAfterCompleteAsync_GETWithResponseBodyAndTrailers_ResetsAfterResponse()
55975607
{
55985608
var startingTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
5609+
var trailersTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
55995610
var appTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
56005611
var clientTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
56015612
var headers = new[]
@@ -5617,6 +5628,9 @@ await InitializeConnectionAsync(async context =>
56175628
context.Response.AppendTrailer("CustomName", "Custom Value");
56185629

56195630
await context.Response.CompleteAsync().DefaultTimeout();
5631+
// Http2FrameWriter sets Trailers.IsReadOnly to true, but since it's a background task we have to wait for something to indicate it ran
5632+
// That something is the client side receiving the trailers.
5633+
await trailersTcs.Task;
56205634

56215635
Assert.True(context.Features.Get<IHttpResponseTrailersFeature>().Trailers.IsReadOnly);
56225636

@@ -5650,6 +5664,7 @@ await InitializeConnectionAsync(async context =>
56505664
withLength: 25,
56515665
withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM),
56525666
withStreamId: 1);
5667+
trailersTcs.SetResult();
56535668
await WaitForStreamErrorAsync(1, Http2ErrorCode.NO_ERROR, expectedErrorMessage:
56545669
"The HTTP/2 stream was reset by the application with error code NO_ERROR.");
56555670

@@ -5678,6 +5693,7 @@ await WaitForStreamErrorAsync(1, Http2ErrorCode.NO_ERROR, expectedErrorMessage:
56785693
public async Task ResetAfterCompleteAsync_POSTWithResponseBodyAndTrailers_RequestBodyThrows()
56795694
{
56805695
var startingTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
5696+
var trailersTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
56815697
var appTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
56825698
var clientTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
56835699
var headers = new[]
@@ -5701,6 +5717,9 @@ await InitializeConnectionAsync(async context =>
57015717
context.Response.AppendTrailer("CustomName", "Custom Value");
57025718

57035719
await context.Response.CompleteAsync().DefaultTimeout();
5720+
// Http2FrameWriter sets Trailers.IsReadOnly to true, but since it's a background task we have to wait for something to indicate it ran
5721+
// That something is the client side receiving the trailers.
5722+
await trailersTcs.Task;
57045723

57055724
Assert.True(context.Features.Get<IHttpResponseTrailersFeature>().Trailers.IsReadOnly);
57065725

@@ -5737,6 +5756,7 @@ await InitializeConnectionAsync(async context =>
57375756
withLength: 25,
57385757
withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM),
57395758
withStreamId: 1);
5759+
trailersTcs.SetResult();
57405760
await WaitForStreamErrorAsync(1, Http2ErrorCode.NO_ERROR, expectedErrorMessage:
57415761
"The HTTP/2 stream was reset by the application with error code NO_ERROR.");
57425762

0 commit comments

Comments
 (0)