From 291a8108761ed347562228f2f8f25477996a5a93 Mon Sep 17 00:00:00 2001 From: Gang Wang Date: Thu, 23 Jan 2025 08:03:48 +0000 Subject: [PATCH] Make the cancelation can be executed before the task is done (#11225) * Make the file large enough so that the cancelation can be executed before the task is done * Use StreamContent to indefinitely provide single char per couple dozens milliseconds * Use a fake stream that provides a single character A~Z per a couple of milliseconds without high memory cost instead * Correct the TimeSpan with Milliseconds * Change the implementation of Read() in the fake stream with simple logic and add a comment --- src/Tasks.UnitTests/DownloadFile_Tests.cs | 40 +++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/Tasks.UnitTests/DownloadFile_Tests.cs b/src/Tasks.UnitTests/DownloadFile_Tests.cs index b2f22466194..398677ca2c9 100644 --- a/src/Tasks.UnitTests/DownloadFile_Tests.cs +++ b/src/Tasks.UnitTests/DownloadFile_Tests.cs @@ -37,7 +37,7 @@ public void CanBeCanceled() DestinationFolder = new TaskItem(folder.Path), HttpMessageHandler = new MockHttpMessageHandler((message, token) => new HttpResponseMessage(HttpStatusCode.OK) { - Content = new StringContent(new String('!', 10000000)), + Content = new StreamContent(new FakeStream()), RequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://largedownload/foo.txt") }), SourceUrl = "http://largedownload/foo.txt" @@ -47,7 +47,7 @@ public void CanBeCanceled() downloadFile.Cancel(); - task.Wait(TimeSpan.FromSeconds(1)).ShouldBeTrue(); + task.Wait(TimeSpan.FromMilliseconds(1500)).ShouldBeTrue(); task.Result.ShouldBeFalse(); } @@ -401,4 +401,40 @@ protected override Task SendAsync(HttpRequestMessage reques } } } + + // Fake stream that simulates providing a single character A~Z per a couple of milliseconds without high memory cost. + public class FakeStream : Stream + { + private readonly int delayMilliseconds; + + public FakeStream(int delayInMilliseconds = 20) + { + delayMilliseconds = delayInMilliseconds; + Position = 0; + } + + public override bool CanRead => true; + public override bool CanSeek => true; + public override bool CanWrite => false; + public override long Length => long.MaxValue; + public override long Position { get; set; } + + public override int Read(byte[] buffer, int offset, int count) + { + // Simulate infinite stream by keeping providing a single character to the beginning of the requested destination. + // Writes next char A ~ Z in alphabet into the begining of requested destination. The count could be ignored. + buffer[offset] = (byte)('A' + Position % 26); + Position++; + Task.Delay(delayMilliseconds).Wait(); + return 1; + } + + public override long Seek(long offset, SeekOrigin origin) => throw new NotImplementedException(); + + public override void SetLength(long value) => throw new NotImplementedException(); + + public override void Write(byte[] buffer, int offset, int count) => throw new NotImplementedException(); + + public override void Flush() => throw new NotImplementedException(); + } }