You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Suppose you are asserting an asynchronous WCF service call - for the sake of simple example just its completion (for complete implementation see NUnitUsingWCFClientDeadlockReproducer.cs.txt)
The problem is that WCF runs asynchronous method completions on the WCF channel dispatcher which seems to be single threaded just like a UI application with a message pump.
…
A sync/async mixture of remoted methods will likely cause deadlocks
Interestingly, our WCF service has only Async methods…
However, Assert.That ends up with a blocking Task.Wait() call and (likely) causes the deadlock.
Solution 1)
To resolve this we have introduced an async variant for Assert.That using DelayedConstraint that looks like this: public static Task DelayedAsync<T>(Func<Task<T>> actualValueDelegate, IResolveConstraint expression, int delayInMilliseconds)
(for complete implementation see DelayedAsync.cs.txt)
Problem 2) - Considering upgrade of NUnit from 2.6.6 -> 3.11
We are running into the issue generally known as "Catching AssertionException fails tests" #2758 but also mentioned in #2043, #2040, #2007.
Analysis 2)
As suggested in those threads, using (new NUnit.Framework.Internal.TestExecutionContext.IsolatedContext()) in the most inner DelayedAsync call resolves the issue.
However, since catching AssertionExceptions is not recommended practise and TestExecutionContext is Internal, I am hesitant to adopt this as a final solution.
We mitigate deadlocks for known synchronization contexts, currently just Windows Forms and WPF message loops. #2917 tracks making this extensible.
Does WCF have a synchronization context and a MessageLoop.Run() and MessageLoop.Exit() equivalent? We might be able to detect it and do everything in the box.
Instead I would wish for a native awaitable Assert.That that would implement async all the way pattern as recommended by Stephen Cleary.
Problem 1)
Suppose you are asserting an asynchronous WCF service call - for the sake of simple example just its completion (for complete implementation see NUnitUsingWCFClientDeadlockReproducer.cs.txt)
In certain cases this lead to deadlock…
Analysis 1)
There is a great article where Alois explains a case of similar WCF deadlock
Interestingly, our WCF service has only Async methods…
However,
Assert.That
ends up with a blockingTask.Wait()
call and (likely) causes the deadlock.Solution 1)
To resolve this we have introduced an async variant for
Assert.That
usingDelayedConstraint
that looks like this:public static Task DelayedAsync<T>(Func<Task<T>> actualValueDelegate, IResolveConstraint expression, int delayInMilliseconds)
(for complete implementation see DelayedAsync.cs.txt)
Problem 2) - Considering upgrade of NUnit from 2.6.6 -> 3.11
We are running into the issue generally known as "Catching AssertionException fails tests" #2758 but also mentioned in #2043, #2040, #2007.
Analysis 2)
As suggested in those threads,
using (new NUnit.Framework.Internal.TestExecutionContext.IsolatedContext())
in the most inner DelayedAsync call resolves the issue.However, since catching AssertionExceptions is not recommended practise and TestExecutionContext is Internal, I am hesitant to adopt this as a final solution.
Instead I would wish for a native awaitable Assert.That that would implement async all the way pattern as recommended by Stephen Cleary.
Looking forward to your feedback and suggestions.
The text was updated successfully, but these errors were encountered: