TimeoutCommand
TimeoutCommand creates a timer in order to cancel
a test if it exceeds a specified time and adjusts
the test result if it did time out.
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal.Abstractions;
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace NUnit.Framework.Internal.Commands
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public class TimeoutCommand : BeforeAndAfterTestCommand
{
private readonly int _timeout;
private readonly IDebugger _debugger;
internal TimeoutCommand(TestCommand innerCommand, int timeout, IDebugger debugger)
: base(innerCommand)
{
_timeout = timeout;
_debugger = debugger;
Guard.ArgumentValid(innerCommand.Test is TestMethod, "TimeoutCommand may only apply to a TestMethod", "innerCommand");
Guard.ArgumentValid(timeout > 0, "Timeout value must be greater than zero", "timeout");
Guard.ArgumentNotNull(debugger, "debugger");
BeforeTest = delegate {
};
AfterTest = delegate {
};
}
public override TestResult Execute(TestExecutionContext context)
{
try {
Task<TestResult> task = RunTestOnSeparateThread(context);
if (Task.WaitAny(new Task[1] {
task
}, _timeout) != -1 || _debugger.IsAttached)
context.CurrentResult = task.GetAwaiter().GetResult();
else {
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(33, 1);
defaultInterpolatedStringHandler.AppendLiteral("Test exceeded Timeout value of ");
defaultInterpolatedStringHandler.AppendFormatted(_timeout);
defaultInterpolatedStringHandler.AppendLiteral("ms");
string message = defaultInterpolatedStringHandler.ToStringAndClear();
context.CurrentResult.SetResult(ResultState.Failure, message);
}
} catch (Exception ex) {
context.CurrentResult.RecordException(ex, FailureSite.Test);
}
return context.CurrentResult;
}
private Task<TestResult> RunTestOnSeparateThread(TestExecutionContext context)
{
TestExecutionContext separateContext = new TestExecutionContext(context) {
CurrentResult = context.CurrentTest.MakeTestResult()
};
return Task.Run(() => innerCommand.Execute(separateContext));
}
}
}