Skip to content

Investigate deadlock, hanging of tests in CI, whether it is CI, F# tasks, TaskSeq CE or XUnit, see also #25 #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
uses: actions/setup-dotnet@v3
# build it, test it, pack it
- name: Run dotnet test - release
run: dotnet test -c Release --blame-hang-timeout 15000ms --logger "trx;LogFileName=test-results-release.trx" --logger "console;verbosity=detailed" .\src\FSharpy.TaskSeq.Test\FSharpy.TaskSeq.Test.fsproj
run: dotnet test -c Release --blame-hang-timeout 60000ms --logger "trx;LogFileName=test-results-release.trx" --logger "console;verbosity=detailed" .\src\FSharpy.TaskSeq.Test\FSharpy.TaskSeq.Test.fsproj
- name: Publish test results - release
uses: dorny/test-reporter@v1
if: always()
Expand All @@ -60,7 +60,7 @@ jobs:
uses: actions/setup-dotnet@v3
# build it, test it, pack it
- name: Run dotnet test - debug
run: dotnet test -c Debug --blame-hang-timeout 15000ms --logger "trx;LogFileName=test-results-debug.trx" --logger "console;verbosity=detailed" .\src\FSharpy.TaskSeq.Test\FSharpy.TaskSeq.Test.fsproj
run: dotnet test -c Debug --blame-hang-timeout 60000ms --logger "trx;LogFileName=test-results-debug.trx" --logger "console;verbosity=detailed" .\src\FSharpy.TaskSeq.Test\FSharpy.TaskSeq.Test.fsproj
- name: Publish test results - debug
uses: dorny/test-reporter@v1
if: always()
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
uses: actions/setup-dotnet@v3
# build it, test it, pack it
- name: Run dotnet test - release
run: dotnet test -c Release --blame-hang-timeout 15000ms --logger "trx;LogFileName=test-results-release.trx" --logger "console;verbosity=detailed" .\src\FSharpy.TaskSeq.Test\FSharpy.TaskSeq.Test.fsproj
run: dotnet test -c Release --blame-hang-timeout 60000ms --logger "trx;LogFileName=test-results-release.trx" --logger "console;verbosity=detailed" .\src\FSharpy.TaskSeq.Test\FSharpy.TaskSeq.Test.fsproj
- name: Publish test results - release
uses: dorny/test-reporter@v1
if: always()
Expand All @@ -41,7 +41,7 @@ jobs:
uses: actions/setup-dotnet@v3
# build it, test it, pack it
- name: Run dotnet test - debug
run: dotnet test -c Debug --blame-hang-timeout 15000ms --logger "trx;LogFileName=test-results-debug.trx" --logger "console;verbosity=detailed" .\src\FSharpy.TaskSeq.Test\FSharpy.TaskSeq.Test.fsproj
run: dotnet test -c Debug --blame-hang-timeout 60000ms --logger "trx;LogFileName=test-results-debug.trx" --logger "console;verbosity=detailed" .\src\FSharpy.TaskSeq.Test\FSharpy.TaskSeq.Test.fsproj
- name: Publish test results - debug
uses: dorny/test-reporter@v1
if: always()
Expand All @@ -50,4 +50,3 @@ jobs:
# this path glob pattern requires forward slashes!
path: ./src/FSharpy.TaskSeq.Test/TestResults/test-results-debug.trx
reporter: dotnet-trx

2 changes: 1 addition & 1 deletion src/FSharpy.TaskSeq.Test/AssemblyInfo.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ namespace FSharpy.Tests

open System.Runtime.CompilerServices

[<assembly: Xunit.CollectionBehavior(DisableTestParallelization = true)>]
[<assembly: Xunit.CollectionBehavior(DisableTestParallelization = false)>]
[<assembly: Xunit.TestCaseOrderer("FSharpy.Tests.AlphabeticalOrderer", "FSharpy.TaskSeq.Test")>]

do ()
1 change: 1 addition & 0 deletions src/FSharpy.TaskSeq.Test/FSharpy.TaskSeq.Test.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<Compile Include="AssemblyInfo.fs" />
<Compile Include="Nunit.Extensions.fs" />
<Compile Include="TestUtils.fs" />
<Compile Include="TaskSeq.AllTests.fs" />
<Compile Include="TaskSeq.Choose.Tests.fs" />
<Compile Include="TaskSeq.Collect.Tests.fs" />
<Compile Include="TaskSeq.Filter.Tests.fs" />
Expand Down
153 changes: 153 additions & 0 deletions src/FSharpy.TaskSeq.Test/TaskSeq.AllTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
namespace FSharpy.Tests

open System
open System.Threading.Tasks
open System.Reflection

open Xunit
open FsUnit.Xunit
open FsToolkit.ErrorHandling

open FSharpy
open Xunit.Abstractions


type AllTests(output: ITestOutputHelper) =
let createParallelRunner () =
let myAsm = Assembly.GetExecutingAssembly()

let allMethods = [
for ty in myAsm.DefinedTypes do
for mem in ty.DeclaredMembers do
match mem.MemberType with
| MemberTypes.Method ->
if mem.Name.StartsWith("TaskSeq") || mem.Name.StartsWith("CE") then
yield ty, mem :?> MethodInfo
| _ -> ()
]

let all = seq {
for (ty, method) in allMethods do
let ctor = ty.GetConstructor [| typeof<ITestOutputHelper> |]

if isNull ctor then
failwith "Constructor for test not found"

let testObj = ctor.Invoke([| output |])

if method.ReturnType.Name.Contains "Task" then
//task {
// let! x = Async.StartChildAsTask (Async.ofTask (method.Invoke(testObj, null) :?> Task<unit>))
// return! x
//}
async {
return!
method.Invoke(testObj, null) :?> Task<unit>
|> Async.AwaitTask
}
else
async { return method.Invoke(testObj, null) |> ignore }
}

all |> Async.Parallel |> Async.map ignore

let multiply f x =
seq {
for i in [ 0..x ] do
yield f ()
}
|> Async.Parallel
|> Async.map ignore

[<Fact>]
let ``Run all tests 1 times in parallel`` () = task { do! multiply createParallelRunner 1 }

[<Theory>]
[<InlineData 1; InlineData 2; InlineData 3; InlineData 4; InlineData 5; InlineData 6; InlineData 7; InlineData 8>]
let ``Run all tests X times in parallel`` i = task { do! multiply createParallelRunner i }

[<Theory>]
[<InlineData 1; InlineData 2; InlineData 3; InlineData 4; InlineData 5; InlineData 6; InlineData 7; InlineData 8>]
let ``Run all tests again X times in parallel`` i = task { do! multiply createParallelRunner i }

[<Theory>]
[<InlineData 1; InlineData 2; InlineData 3; InlineData 4; InlineData 5; InlineData 6; InlineData 7; InlineData 8>]
let ``Run all tests and once more, X times in parallel`` i = task { do! multiply createParallelRunner i }


//[<Fact>]
//let ``Run all tests 3 times in parallel`` () =
// multiply createParallelRunner 15
// |> Async.RunSynchronously


//[<Fact>]
//let ``Run all tests 4 times in parallel`` () =
// multiply createParallelRunner 15
// |> Async.RunSynchronously


//[<Fact>]
//let ``Run all tests 5 times in parallel`` () =
// multiply createParallelRunner 15
// |> Async.RunSynchronously


//[<Fact>]
//let ``Run all tests 6 times in parallel`` () =
// multiply createParallelRunner 15
// |> Async.RunSynchronously


//[<Fact>]
//let ``Run all tests 7 times in parallel`` () =
// multiply createParallelRunner 15
// |> Async.RunSynchronously


//[<Fact>]
//let ``Run all tests 8 times in parallel`` () =
// multiply createParallelRunner 15
// |> Async.RunSynchronously


//[<Fact>]
//let ``Run all tests 9 times in parallel`` () =
// multiply createParallelRunner 15
// |> Async.RunSynchronously


//[<Fact>]
//let ``Run all tests 10 times in parallel`` () =
// multiply createParallelRunner 15
// |> Async.RunSynchronously


//[<Fact>]
//let ``Run all tests 11 times in parallel`` () =
// multiply createParallelRunner 15
// |> Async.RunSynchronously


//[<Fact>]
//let ``Run all tests 12 times in parallel`` () =
// multiply createParallelRunner 15
// |> Async.RunSynchronously


//[<Fact>]
//let ``Run all tests 13 times in parallel`` () =
// multiply createParallelRunner 15
// |> Async.RunSynchronously


//[<Fact>]
//let ``Run all tests 14 times in parallel`` () =
// multiply createParallelRunner 15
// |> Async.RunSynchronously


//[<Fact>]
//let ``Run all tests 15 times in parallel`` () =
// multiply createParallelRunner 15
// |> Async.RunSynchronously
112 changes: 65 additions & 47 deletions src/FSharpy.TaskSeq.Test/TaskSeq.Choose.Tests.fs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module FSharpy.Tests.Choose
namespace FSharpy.Tests

open System
open System.Threading.Tasks
Expand All @@ -8,50 +8,68 @@ open FsUnit.Xunit
open FsToolkit.ErrorHandling

open FSharpy
open Xunit.Abstractions

[<Fact>]
let ``ZHang timeout test`` () = task {
let! empty = Task.Delay 30

empty |> should be Null
}

[<Fact>]
let ``TaskSeq-choose on an empty sequence`` () = task {
let! empty =
TaskSeq.empty
|> TaskSeq.choose (fun _ -> Some 42)
|> TaskSeq.toListAsync

List.isEmpty empty |> should be True
}

[<Fact>]
let ``TaskSeq-chooseAsync on an empty sequence`` () = task {
let! empty =
TaskSeq.empty
|> TaskSeq.chooseAsync (fun _ -> task { return Some 42 })
|> TaskSeq.toListAsync

List.isEmpty empty |> should be True
}

[<Fact>]
let ``TaskSeq-choose can convert and filter`` () = task {
let! alphabet =
createDummyTaskSeqWith 50L<µs> 1000L<µs> 50
|> TaskSeq.choose (fun number -> if number <= 26 then Some(char number + '@') else None)
|> TaskSeq.toArrayAsync

String alphabet |> should equal "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
}

[<Fact>]
let ``TaskSeq-chooseAsync can convert and filter`` () = task {
let! alphabet =
createDummyTaskSeqWith 50L<µs> 1000L<µs> 50
|> TaskSeq.choose (fun number -> if number <= 26 then Some(char number + '@') else None)
|> TaskSeq.toArrayAsync

String alphabet |> should equal "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
}

type Choose(output: ITestOutputHelper) =

[<Fact(Skip = "CI test runner chokes!")>]
let ``ZHang timeout test`` () =
logStart output

task {
let! empty = Task.Delay 30
empty |> should be Null
}

[<Fact(Skip = "CI test runner chokes!")>]
let ``TaskSeq-choose on an empty sequence`` () =
logStart output

task {
let! empty =
TaskSeq.empty
|> TaskSeq.choose (fun _ -> Some 42)
|> TaskSeq.toListAsync

List.isEmpty empty |> should be True
}

[<Fact(Skip = "CI test runner chokes!")>]
let ``TaskSeq-chooseAsync on an empty sequence`` () =
logStart output

task {
let! empty =
TaskSeq.empty
|> TaskSeq.chooseAsync (fun _ -> task { return Some 42 })
|> TaskSeq.toListAsync

List.isEmpty empty |> should be True
}

[<Fact(Skip = "CI test runner chokes!")>]
let ``TaskSeq-choose can convert and filter`` () =
logStart output

task {
let! alphabet =
createDummyTaskSeqWith 50L<µs> 1000L<µs> 50
|> TaskSeq.choose (fun number -> if number <= 26 then Some(char number + '@') else None)
|> TaskSeq.toArrayAsync

String alphabet |> should equal "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
}

[<Fact(Skip = "CI test runner chokes!")>]
let ``TaskSeq-chooseAsync can convert and filter`` () =
logStart output

task {
let! alphabet =
createDummyTaskSeqWith 50L<µs> 1000L<µs> 50
|> TaskSeq.choose (fun number -> if number <= 26 then Some(char number + '@') else None)
|> TaskSeq.toArrayAsync

String alphabet |> should equal "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
}
Loading