From c322b873ed9828fcb010863b0ce63e6358778524 Mon Sep 17 00:00:00 2001 From: Fraser Waters Date: Thu, 29 Aug 2019 18:07:03 +0100 Subject: [PATCH 1/2] Change cancellation test to not depend on how AwaitTask works This test is to check that when an Async is started as a Task (via StartAsTask) that when cancelled the Task isn't immediately marked as cancelled but instead waits for the underlying Async to finish (normally via cancellation) --- .../Microsoft.FSharp.Control/AsyncType.fs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs index c0797038f56..100ea0b6922 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs @@ -145,10 +145,12 @@ type AsyncType() = [] member this.StartAsTaskCancellation () = let cts = new CancellationTokenSource() - let tcs = TaskCompletionSource() + let mutable spinloop = true + let doSpinloop () = while spinloop do () let a = async { cts.CancelAfter (100) - do! tcs.Task |> Async.AwaitTask } + doSpinloop() + } #if !NET46 let t : Task = #else @@ -156,13 +158,13 @@ type AsyncType() = #endif Async.StartAsTask(a, cancellationToken = cts.Token) - // Should not finish + // Should not finish, we don't eagerly mark the task done just because it's been signaled to cancel. try let result = t.Wait(300) Assert.IsFalse (result) - with :? AggregateException -> Assert.Fail "Task should not finish, jet" + with :? AggregateException -> Assert.Fail "Task should not finish, yet" - tcs.SetCanceled() + spinloop <- false try this.WaitASec t From 75500f176803b4f4f370313d59f8f0c2375d66ff Mon Sep 17 00:00:00 2001 From: Fraser Waters Date: Thu, 29 Aug 2019 19:29:20 +0100 Subject: [PATCH 2/2] Add test that AwaitTask ignore async cancellation --- .../Microsoft.FSharp.Control/AsyncType.fs | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs index 100ea0b6922..79a179bea1e 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs @@ -150,7 +150,7 @@ type AsyncType() = let a = async { cts.CancelAfter (100) doSpinloop() - } + } #if !NET46 let t : Task = #else @@ -174,6 +174,31 @@ type AsyncType() = | _ -> reraise() Assert.IsTrue (t.IsCompleted, "Task is not completed") + [] + member this.``AwaitTask ignores Async cancellation`` () = + let cts = new CancellationTokenSource() + let tcs = new TaskCompletionSource() + let innerTcs = new TaskCompletionSource() + let a = innerTcs.Task |> Async.AwaitTask + + Async.StartWithContinuations(a, tcs.SetResult, tcs.SetException, ignore >> tcs.SetCanceled, cts.Token) + + cts.CancelAfter(100) + try + let result = tcs.Task.Wait(300) + Assert.IsFalse (result) + with :? AggregateException -> Assert.Fail "Should not finish, yet" + + innerTcs.SetResult () + + try + this.WaitASec tcs.Task + with :? AggregateException as a -> + match a.InnerException with + | :? TaskCanceledException -> () + | _ -> reraise() + Assert.IsTrue (tcs.Task.IsCompleted, "Task is not completed") + [] member this.StartTask () = let s = "Hello tasks!"