From b61e247beb307ba851daf02084c8d4e14bbc4d06 Mon Sep 17 00:00:00 2001 From: Jeremy Barton Date: Wed, 14 Sep 2022 11:26:01 -0700 Subject: [PATCH 1/3] Use determinism instead of timing in cancellation tests --- .../tests/HashAlgorithmTest.cs | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTest.cs b/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTest.cs index 015f36c8a979f7..c8bcdacce5be0d 100644 --- a/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTest.cs +++ b/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTest.cs @@ -62,19 +62,22 @@ public async Task VerifyComputeHashAsync(int size) [ActiveIssue("https://github.com/dotnet/runtime/issues/37669", TestPlatforms.Browser)] public async Task ComputeHashAsync_SupportsCancellation() { - using (CancellationTokenSource cancellationSource = new CancellationTokenSource(100)) - using (PositionValueStream stream = new SlowPositionValueStream(10000)) + using (CancellationTokenSource cancellationSource = new CancellationTokenSource()) + using (PositionValueStream stream = new SelfCancellingStream(10000, cancellationSource)) using (HashAlgorithm hash = new SummingTestHashAlgorithm()) { await Assert.ThrowsAnyAsync( () => hash.ComputeHashAsync(stream, cancellationSource.Token)); + + Assert.True(cancellationSource.IsCancellationRequested); } } [Fact] public void ComputeHashAsync_Disposed() { - using (PositionValueStream stream = new SlowPositionValueStream(10000)) + using (CancellationTokenSource cancellationSource = new CancellationTokenSource()) + using (PositionValueStream stream = new SelfCancellingStream(10000, cancellationSource)) using (HashAlgorithm hash = new SummingTestHashAlgorithm()) { hash.Dispose(); @@ -85,6 +88,10 @@ public void ComputeHashAsync_Disposed() // Not returning or awaiting the Task, it never got created. hash.ComputeHashAsync(stream); }); + + // If SelfCancellingStream.Read (or ReadAsync) was called it will trip cancellation, + // so use that as a signal for whether or not the stream was ever read from. + Assert.False(cancellationSource.IsCancellationRequested, "Stream.Read was invoked"); } } @@ -123,15 +130,19 @@ protected override void HashCore(byte[] array, int ibStart, int cbSize) // implementations by verifying the right value is produced. } - private class SlowPositionValueStream : PositionValueStream + private class SelfCancellingStream : PositionValueStream { - public SlowPositionValueStream(int totalCount) : base(totalCount) + private readonly CancellationTokenSource _cancellationSource; + + public SelfCancellingStream(int totalCount, CancellationTokenSource cancellationSource) + : base(totalCount) { + _cancellationSource = cancellationSource; } public override int Read(byte[] buffer, int offset, int count) { - System.Threading.Thread.Sleep(1000); + _cancellationSource.Cancel(throwOnFirstException: true); return base.Read(buffer, offset, count); } } From f314ed04daefea335d3f9990d9d790eb16ce0471 Mon Sep 17 00:00:00 2001 From: Jeremy Barton Date: Wed, 14 Sep 2022 11:34:31 -0700 Subject: [PATCH 2/3] Add an explanatory comment to the test. --- .../System.Security.Cryptography/tests/HashAlgorithmTest.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTest.cs b/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTest.cs index c8bcdacce5be0d..a801e017068d7a 100644 --- a/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTest.cs +++ b/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTest.cs @@ -66,6 +66,11 @@ public async Task ComputeHashAsync_SupportsCancellation() using (PositionValueStream stream = new SelfCancellingStream(10000, cancellationSource)) using (HashAlgorithm hash = new SummingTestHashAlgorithm()) { + // The stream has a length longer than ComputeHashAsync's read buffer, + // so ReadAsync will get called multiple times. + // The first call succeeds, but moves the cancellation source to canceled, + // and the second call then fails with an OperationCanceledException, cancelling the + // whole operation. await Assert.ThrowsAnyAsync( () => hash.ComputeHashAsync(stream, cancellationSource.Token)); From 71f1d587f7c3cc9322fdc13ae220bdee1b0972ff Mon Sep 17 00:00:00 2001 From: Jeremy Barton Date: Wed, 14 Sep 2022 11:50:56 -0700 Subject: [PATCH 3/3] Spell "canceling" with only one L. --- .../tests/HashAlgorithmTest.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTest.cs b/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTest.cs index a801e017068d7a..acd7df3a9f8077 100644 --- a/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTest.cs +++ b/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTest.cs @@ -63,13 +63,13 @@ public async Task VerifyComputeHashAsync(int size) public async Task ComputeHashAsync_SupportsCancellation() { using (CancellationTokenSource cancellationSource = new CancellationTokenSource()) - using (PositionValueStream stream = new SelfCancellingStream(10000, cancellationSource)) + using (PositionValueStream stream = new SelfCancelingStream(10000, cancellationSource)) using (HashAlgorithm hash = new SummingTestHashAlgorithm()) { // The stream has a length longer than ComputeHashAsync's read buffer, // so ReadAsync will get called multiple times. // The first call succeeds, but moves the cancellation source to canceled, - // and the second call then fails with an OperationCanceledException, cancelling the + // and the second call then fails with an OperationCanceledException, canceling the // whole operation. await Assert.ThrowsAnyAsync( () => hash.ComputeHashAsync(stream, cancellationSource.Token)); @@ -82,7 +82,7 @@ await Assert.ThrowsAnyAsync( public void ComputeHashAsync_Disposed() { using (CancellationTokenSource cancellationSource = new CancellationTokenSource()) - using (PositionValueStream stream = new SelfCancellingStream(10000, cancellationSource)) + using (PositionValueStream stream = new SelfCancelingStream(10000, cancellationSource)) using (HashAlgorithm hash = new SummingTestHashAlgorithm()) { hash.Dispose(); @@ -94,7 +94,7 @@ public void ComputeHashAsync_Disposed() hash.ComputeHashAsync(stream); }); - // If SelfCancellingStream.Read (or ReadAsync) was called it will trip cancellation, + // If SelfCancelingStream.Read (or ReadAsync) was called it will trip cancellation, // so use that as a signal for whether or not the stream was ever read from. Assert.False(cancellationSource.IsCancellationRequested, "Stream.Read was invoked"); } @@ -135,11 +135,11 @@ protected override void HashCore(byte[] array, int ibStart, int cbSize) // implementations by verifying the right value is produced. } - private class SelfCancellingStream : PositionValueStream + private class SelfCancelingStream : PositionValueStream { private readonly CancellationTokenSource _cancellationSource; - public SelfCancellingStream(int totalCount, CancellationTokenSource cancellationSource) + public SelfCancelingStream(int totalCount, CancellationTokenSource cancellationSource) : base(totalCount) { _cancellationSource = cancellationSource;