-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathTaskSeq.PocTests.fs
More file actions
93 lines (72 loc) · 3.34 KB
/
TaskSeq.PocTests.fs
File metadata and controls
93 lines (72 loc) · 3.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
namespace TaskSeq.Tests
open Xunit
open FsUnit.Xunit
open FsToolkit.ErrorHandling
open FSharp.Control
/////////////////////////////////////////////////////////////////////////////
/// ///
/// This file contains bunch of tests that exemplify how hard it can be ///
/// to use IAsyncEnumarable "by hand", and how mistakes can be made ///
/// that can lead to occasional failings ///
/// ///
/////////////////////////////////////////////////////////////////////////////
module ``PoC's for seq of tasks`` =
[<Fact>]
let ``Good: Show joining tasks with continuation is good`` () = task {
// acts like a fold
let! results = Gen.createAndJoinMultipleTasks 10 Gen.joinWithContinuation
results |> should equal 10
}
[<Fact>]
let ``Good: Show that joining tasks with 'bind' in task CE is good`` () = task {
let! tasks = Gen.createAndJoinMultipleTasks 10 Gen.joinIdentityDelayed
let tasks = tasks |> Array.ofList
let len = Array.length tasks
let results = Array.zeroCreate len
for i in 0 .. len - 1 do
// this uses Task.bind under the hood, which ensures order-of-execution and wait-for-previous
let! item = tasks[i]() // only now are we delay-executing the task in the array
results[i] <- item
results |> should equal <| Array.init len ((+) 1)
}
[<Fact>]
let ``Good: Show that joining tasks with 'taskSeq' is good`` () = task {
let! tasks = Gen.createAndJoinMultipleTasks 10 Gen.joinIdentityDelayed
let asAsyncSeq = taskSeq {
for task in tasks do
// cannot use `yield!` here, as `taskSeq` expects it to return a seq
let! x = task ()
yield x
}
let! results = asAsyncSeq |> TaskSeq.toArrayAsync
results |> should equal
<| Array.init (Array.length results) ((+) 1)
}
[<Fact>]
let ``Bad: Show that joining tasks with 'traverseTaskResult' can be bad`` () = task {
let! taskList = Gen.createAndJoinMultipleTasks 10 Gen.joinIdentityHotStarted
// since tasks are hot-started, by this time they are already *all* running
let! results =
taskList
|> List.map (Task.map Result<int, string>.Ok)
|> List.traverseTaskResultA id
match results with
| Ok results ->
// BAD!! As you can see, results are unequal to expected output
results |> should not'
<| equal (List.init (List.length results) ((+) 1))
| Error err -> failwith $"Impossible: {err}"
}
[<Fact>]
let ``Bad: Show that joining tasks as a list of tasks can be bad`` () = task {
let! taskList = Gen.createAndJoinMultipleTasks 10 Gen.joinIdentityHotStarted
// since tasks are hot-started, by this time they are already *all* running
let tasks = taskList |> Array.ofList
let results = Array.zeroCreate 10
for i in 0..9 do
let! item = tasks[i]
results[i] <- item
// BAD!! As you can see, results are unequal to expected output
results |> should not'
<| equal (Array.init (Array.length results) ((+) 1))
}