Skip to content

Commit 140ed27

Browse files
committed
Add capability to failfast when a test takes longer than expected
1 parent aeb57b3 commit 140ed27

File tree

4 files changed

+60
-3
lines changed

4 files changed

+60
-3
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
3+
4+
namespace Infrastructure.Common
5+
{
6+
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = false)]
7+
public class FailFastAfterAttribute : Attribute
8+
{
9+
public FailFastAfterAttribute(string durationString)
10+
{
11+
FailTime = TimeSpan.Parse(durationString);
12+
}
13+
14+
public TimeSpan FailTime { get; }
15+
}
16+
}

src/System.Private.ServiceModel/tests/Common/Infrastructure/xunit/WcfTestCase.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ internal class WcfTestCase : XunitTestCase, IXunitTestCase
2020
{
2121
private string _skippedReason;
2222
private bool _isTheory;
23+
private readonly TimeSpan _failFastDuration;
2324
private readonly IMessageSink _diagnosticMessageSink;
2425

2526
static TestEventListener s_testListener = new TestEventListener(new List<string>() { "Microsoft-Windows-Application Server-Applications" }, EventLevel.Verbose);
@@ -31,13 +32,15 @@ public WcfTestCase()
3132

3233
internal WcfTestCase(XunitTestCase testCase,
3334
TestMethodDisplay defaultMethodDisplay,
35+
TimeSpan failFastDuration,
3436
string skippedReason = null,
3537
bool isTheory = false,
3638
IMessageSink diagnosticMessageSink = null)
3739
: base(diagnosticMessageSink, defaultMethodDisplay, TestMethodDisplayOptions.None, testCase.TestMethod, testCase.TestMethodArguments)
3840
{
3941
_skippedReason = skippedReason;
4042
_isTheory = isTheory;
43+
_failFastDuration = failFastDuration;
4144
_diagnosticMessageSink = diagnosticMessageSink;
4245
}
4346

@@ -47,9 +50,21 @@ public override async Task<RunSummary> RunAsync(
4750
{
4851
ConcurrentQueue<EventWrittenEventArgs> events = new ConcurrentQueue<EventWrittenEventArgs>();
4952
s_testListener.EventWritten = events.Enqueue;
53+
Timer timer = null;
54+
if (_failFastDuration != System.Threading.Timeout.InfiniteTimeSpan)
55+
{
56+
timer = new Timer((s) => Environment.FailFast("Test timed out"),
57+
null,
58+
(int)_failFastDuration.TotalMilliseconds,
59+
System.Threading.Timeout.Infinite);
60+
}
5061

51-
RunSummary runsummary = await (_isTheory ? new XunitTheoryTestCaseRunner(this, DisplayName, _skippedReason, constructorArguments, _diagnosticMessageSink, messageBus, aggregator, cancellationTokenSource).RunAsync()
52-
: new XunitTestCaseRunner(this, DisplayName, _skippedReason, constructorArguments, TestMethodArguments, messageBus, aggregator, cancellationTokenSource).RunAsync());
62+
RunSummary runsummary;
63+
using (timer)
64+
{
65+
runsummary = await (_isTheory ? new XunitTheoryTestCaseRunner(this, DisplayName, _skippedReason, constructorArguments, _diagnosticMessageSink, messageBus, aggregator, cancellationTokenSource).RunAsync()
66+
: new XunitTestCaseRunner(this, DisplayName, _skippedReason, constructorArguments, TestMethodArguments, messageBus, aggregator, cancellationTokenSource).RunAsync());
67+
}
5368

5469
s_testListener.EventWritten = null;
5570
if (runsummary.Failed > 0 && events.Count > 0)

src/System.Private.ServiceModel/tests/Common/Infrastructure/xunit/WcfTestDiscoverer.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Collections.Generic;
77
using System.Linq;
88
using System.Reflection;
9+
using System.Threading;
910
using Xunit.Abstractions;
1011
using Xunit.Sdk;
1112

@@ -47,13 +48,14 @@ internal static IEnumerable<IXunitTestCase> Discover(
4748
string skippedReason = string.Format("Active issue(s): {0}", string.Join(", ", issueSkipList));
4849
return testCases.Select(tc => new WcfTestCase((XunitTestCase)tc,
4950
discoveryOptions.MethodDisplayOrDefault(),
51+
Timeout.InfiniteTimeSpan,
5052
skippedReason,
5153
isTheory,
5254
diagnosticMessageSink));
5355
}
5456
}
5557

56-
// Finally evaluate all the [Condition] attributes. These will execute code
58+
// Evaluate all the [Condition] attributes. These will execute code
5759
// that determines whether this test should be run or skipped.
5860
ConditionAttribute[] conditions = testMethodInfo.GetCustomAttributes<ConditionAttribute>().ToArray();
5961
if (conditions.Length > 0)
@@ -75,17 +77,39 @@ internal static IEnumerable<IXunitTestCase> Discover(
7577
string skippedReason = string.Format("Condition(s) not met: {0}", string.Join(", ", skipReasons));
7678
return testCases.Select(tc => new WcfTestCase((XunitTestCase)tc,
7779
discoveryOptions.MethodDisplayOrDefault(),
80+
Timeout.InfiniteTimeSpan,
7881
skippedReason,
7982
isTheory,
8083
diagnosticMessageSink));
8184
}
8285
}
8386

87+
// Look for FailFastAfterAttribute applied to the test method
88+
FailFastAfterAttribute failFastAttribute = testMethodInfo.GetCustomAttribute<FailFastAfterAttribute>();
89+
if (failFastAttribute == null)
90+
{
91+
// If it's not found on the method, check the class
92+
failFastAttribute = testMethodInfo.DeclaringType.GetCustomAttribute<FailFastAfterAttribute>();
93+
}
94+
95+
if (failFastAttribute == null)
96+
{
97+
// If it's not found on the method or class, check the assembly
98+
failFastAttribute = testMethodInfo.DeclaringType.Assembly.GetCustomAttribute<FailFastAfterAttribute>();
99+
}
100+
101+
TimeSpan failFastDuration = Timeout.InfiniteTimeSpan;
102+
if (failFastAttribute != null)
103+
{
104+
failFastDuration = failFastAttribute.FailTime;
105+
}
106+
84107
// If we get this far, we have decided to run the test.
85108
// Still wrap it in a WcfTestCase with a null skip message
86109
// so that other WcfTestCase customizations are used.
87110
return testCases.Select(tc => new WcfTestCase(testCase: (XunitTestCase)tc,
88111
defaultMethodDisplay: discoveryOptions.MethodDisplayOrDefault(),
112+
failFastDuration: failFastDuration,
89113
skippedReason: null,
90114
isTheory: isTheory,
91115
diagnosticMessageSink: diagnosticMessageSink));

src/System.Private.ServiceModel/tests/Scenarios/Client/ClientBase/ChannelBaseTests.4.0.0.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
using Infrastructure.Common;
99
using Xunit;
1010

11+
[assembly: FailFastAfter("00:01:00")]
12+
1113
public static partial class ChannelBaseTests_4_0_0
1214
{
1315
[WcfFact]

0 commit comments

Comments
 (0)