|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
using System.Threading;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using Xunit.Abstractions;
|
|
|
|
|
|
using Xunit.Sdk;
|
|
|
|
|
|
|
|
|
|
|
|
namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit;
|
|
|
|
|
|
|
|
|
|
|
|
public class JetXunitTestCaseRunner(
|
|
|
|
|
|
IXunitTestCase testCase,
|
|
|
|
|
|
string displayName,
|
|
|
|
|
|
string skipReason,
|
|
|
|
|
|
object[] constructorArguments,
|
|
|
|
|
|
object[] testMethodArguments,
|
|
|
|
|
|
IMessageBus messageBus,
|
|
|
|
|
|
ExceptionAggregator aggregator,
|
|
|
|
|
|
CancellationTokenSource cancellationTokenSource)
|
|
|
|
|
|
: XunitTestCaseRunner(testCase,
|
|
|
|
|
|
displayName,
|
|
|
|
|
|
skipReason,
|
|
|
|
|
|
constructorArguments,
|
|
|
|
|
|
testMethodArguments,
|
|
|
|
|
|
messageBus,
|
|
|
|
|
|
aggregator,
|
|
|
|
|
|
cancellationTokenSource)
|
|
|
|
|
|
{
|
|
|
|
|
|
public const string TestRunnerCrashCacheDirectory = "TestRunnerCrashCache";
|
|
|
|
|
|
public const string AutoSkipPrefix = "[AutoSkip]";
|
|
|
|
|
|
public const string AutoSkipTestRunnerCrashingTestsEnvironmentVariableName = "EFCoreJet_AutoSkipTestRunnerCrashingTests";
|
|
|
|
|
|
|
|
|
|
|
|
public virtual bool EnableAutoSkipTestsKnownToCrashTestRunner
|
|
|
|
|
|
=> (Environment.GetEnvironmentVariable(AutoSkipTestRunnerCrashingTestsEnvironmentVariableName)?.ToLowerInvariant() ?? "true") != "false";
|
|
|
|
|
|
|
|
|
|
|
|
protected override XunitTestRunner CreateTestRunner(ITest test,
|
|
|
|
|
|
IMessageBus messageBus,
|
|
|
|
|
|
Type testClass,
|
|
|
|
|
|
object[] constructorArguments,
|
|
|
|
|
|
MethodInfo testMethod,
|
|
|
|
|
|
object[] testMethodArguments,
|
|
|
|
|
|
string skipReason,
|
|
|
|
|
|
IReadOnlyList<BeforeAfterTestAttribute> beforeAfterAttributes,
|
|
|
|
|
|
ExceptionAggregator aggregator,
|
|
|
|
|
|
CancellationTokenSource cancellationTokenSource)
|
|
|
|
|
|
=> new JetXunitTestRunner(
|
|
|
|
|
|
test,
|
|
|
|
|
|
messageBus,
|
|
|
|
|
|
testClass,
|
|
|
|
|
|
constructorArguments,
|
|
|
|
|
|
testMethod,
|
|
|
|
|
|
testMethodArguments,
|
|
|
|
|
|
skipReason,
|
|
|
|
|
|
beforeAfterAttributes,
|
|
|
|
|
|
new ExceptionAggregator(aggregator),
|
|
|
|
|
|
cancellationTokenSource);
|
|
|
|
|
|
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// `TestRunner<TTestCase>.RunAsync()` is not virtual, so we need to override this method here to call our own
|
|
|
|
|
|
/// `JetXunitTestRunner.RunAsync()` implementation.
|
|
|
|
|
|
/// </remarks>>
|
|
|
|
|
|
protected override async Task<RunSummary> RunTestAsync()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (EnableAutoSkipTestsKnownToCrashTestRunner)
|
|
|
|
|
|
{
|
|
|
|
|
|
AutoSkipTestsKnownToCrashTestRunner();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return await RunWithCrashDetection(
|
|
|
|
|
|
() => ((JetXunitTestRunner)CreateTestRunner(
|
|
|
|
|
|
CreateTest(TestCase, DisplayName),
|
|
|
|
|
|
MessageBus,
|
|
|
|
|
|
TestClass,
|
|
|
|
|
|
ConstructorArguments,
|
|
|
|
|
|
TestMethod,
|
|
|
|
|
|
TestMethodArguments,
|
|
|
|
|
|
SkipReason,
|
|
|
|
|
|
BeforeAfterAttributes,
|
|
|
|
|
|
Aggregator,
|
|
|
|
|
|
CancellationTokenSource))
|
|
|
|
|
|
.RunAsync());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual async Task<RunSummary> RunWithCrashDetection(Func<Task<RunSummary>> func)
|
|
|
|
|
|
{
|
|
|
|
|
|
Directory.CreateDirectory(TestRunnerCrashCacheDirectory);
|
|
|
|
|
|
|
|
|
|
|
|
var filePath = Path.Combine(TestRunnerCrashCacheDirectory, $"{DateTime.UtcNow:yyyyMMdd'_'HHmmss.fffffff}_{(Environment.Is64BitProcess ? "x64" : "x86")}_{Guid.NewGuid()}.txt");
|
|
|
|
|
|
var contents = $"{TestCase.TestMethod.TestClass.Class.Name}\t{TestCase.TestMethod.Method.Name}";
|
|
|
|
|
|
await File.WriteAllTextAsync(filePath, contents);
|
|
|
|
|
|
|
|
|
|
|
|
var result = await func();
|
|
|
|
|
|
|
|
|
|
|
|
File.Delete(filePath);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual void AutoSkipTestsKnownToCrashTestRunner()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (IsTestKnownToCrashTestRunner(TestCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
SkipReason = $"{AutoSkipPrefix} {TestRunnerCrashAttribute.DefaultSkipReason}";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual bool IsTestKnownToCrashTestRunner(ITestCase testCase)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (File.Exists(JetXunitTestFramework.TestsKnownToCrashTestRunnerFilePath))
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var line in File.ReadLines(JetXunitTestFramework.TestsKnownToCrashTestRunnerFilePath))
|
|
|
|
|
|
{
|
|
|
|
|
|
var parts = line.Split('\t');
|
|
|
|
|
|
if (parts.Length >= 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
var testClass = parts[^2];
|
|
|
|
|
|
var testMethod = parts[^1];
|
|
|
|
|
|
|
|
|
|
|
|
if (testClass == testCase.TestMethod.TestClass.Class.Name &&
|
|
|
|
|
|
testMethod == testCase.TestMethod.Method.Name)
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|