Skip to content
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

Optimize creation of test-thread context using test framework independent resource pooling #144

Merged
merged 6 commits into from
Jun 12, 2024
Merged
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
## Improvements:

* Reqnroll.Verify: Support for Verify v24 (Verify.Xunit v24.2.0) for .NET 4.7.2+ and .NET 6.0+. For earlier versions of Verify or for .NET 4.6.2, use the latest 2.0.3 version of the plugin that is compatible with Reqnroll v2.*. (#151)
* Optimize creation of test-thread context using test framework independent resource pooling (#144)

## Bug fixes:

*Contributors of this release (in alphabetical order):* @ajeckmans
*Contributors of this release (in alphabetical order):* @ajeckmans, @obligaron

# v2.0.3 - 2024-06-10

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Public NotInheritable Class PROJECT_ROOT_NAMESPACE_MSTestAssemblyHooks
Public Shared Async Function AssemblyInitializeAsync(testContext As TestContext) As Task
Dim currentAssembly As Assembly = GetType(PROJECT_ROOT_NAMESPACE_MSTestAssemblyHooks).Assembly
Dim containerBuilder As New MsTestContainerBuilder(testContext)
Await Global.Reqnroll.TestRunnerManager.OnTestRunStartAsync(currentAssembly, Nothing, containerBuilder)
Await Global.Reqnroll.TestRunnerManager.OnTestRunStartAsync(currentAssembly, containerBuilder)
End Function

<AssemblyCleanup>
Expand Down

This file was deleted.

17 changes: 9 additions & 8 deletions Reqnroll.Generator/Generation/UnitTestFeatureGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,15 +177,9 @@ private void SetupTestClassInitializeMethod(TestClassGenerationContext generatio
//testRunner = TestRunnerManager.GetTestRunnerForAssembly(null, [test_worker_id]);
var testRunnerField = _scenarioPartHelper.GetTestRunnerExpression();

var testRunnerParameters = new[]
{
new CodePrimitiveExpression(null),
_testGeneratorProvider.GetTestWorkerIdExpression()
};

var getTestRunnerExpression = new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression(_codeDomHelper.GetGlobalizedTypeName(typeof(TestRunnerManager))),
nameof(TestRunnerManager.GetTestRunnerForAssembly), testRunnerParameters);
nameof(TestRunnerManager.GetTestRunnerForAssembly));

testClassInitializeMethod.Statements.Add(
new CodeAssignStatement(
Expand Down Expand Up @@ -238,7 +232,14 @@ private void SetupTestClassCleanupMethod(TestClassGenerationContext generationCo
_codeDomHelper.MarkCodeMethodInvokeExpressionAsAwait(expression);

testClassCleanupMethod.Statements.Add(expression);


//
testClassCleanupMethod.Statements.Add(
new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression(_codeDomHelper.GetGlobalizedTypeName(typeof(TestRunnerManager))),
nameof(TestRunnerManager.ReleaseTestRunner),
testRunnerField));

// testRunner = null;
testClassCleanupMethod.Statements.Add(
new CodeAssignStatement(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,5 @@ public interface IUnitTestGeneratorProvider
void SetTestMethodAsRow(TestClassGenerationContext generationContext, CodeMemberMethod testMethod, string scenarioTitle, string exampleSetName, string variantName, IEnumerable<KeyValuePair<string, string>> arguments);

void MarkCodeMethodInvokeExpressionAsAwait(CodeMethodInvokeExpression expression);

CodeExpression GetTestWorkerIdExpression();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -228,14 +228,5 @@ public void MarkCodeMethodInvokeExpressionAsAwait(CodeMethodInvokeExpression exp
{
CodeDomHelper.MarkCodeMethodInvokeExpressionAsAwait(expression);
}

public CodeExpression GetTestWorkerIdExpression()
{
// System.Threading.Thread.CurrentThread.ManagedThreadId.ToString()
return new CodeMethodInvokeExpression(
new CodeVariableReferenceExpression("System.Threading.Thread.CurrentThread.ManagedThreadId"),
nameof(ToString)
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,5 @@ public void MarkCodeMethodInvokeExpressionAsAwait(CodeMethodInvokeExpression exp
{
CodeDomHelper.MarkCodeMethodInvokeExpressionAsAwait(expression);
}

public CodeExpression GetTestWorkerIdExpression()
=> new CodePropertyReferenceExpression(GetTestContextExpression(), TESTCONTEXT_WORKERID_PROPERTY);
}
}
22 changes: 0 additions & 22 deletions Reqnroll.Generator/UnitTestProvider/XUnit2TestGeneratorProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public class XUnit2TestGeneratorProvider : IUnitTestGeneratorProvider
protected internal const string IGNORE_TEST_CLASS = "IgnoreTestClass";
protected internal const string NONPARALLELIZABLE_COLLECTION_NAME = "ReqnrollNonParallelizableFeatures";
protected internal const string IASYNCLIFETIME_INTERFACE = "Xunit.IAsyncLifetime";
protected internal const string XUNITPARALLELWORKERTRACKER_INSTANCE = "Reqnroll.xUnit.ReqnrollPlugin.XUnitParallelWorkerTracker.Instance";

public XUnit2TestGeneratorProvider(CodeDomHelper codeDomHelper)
{
Expand Down Expand Up @@ -178,19 +177,6 @@ public virtual void FinalizeTestClass(TestClassGenerationContext generationConte
nameof(IObjectContainer.RegisterInstanceAs),
new CodeTypeReference(OUTPUT_INTERFACE)),
new CodeVariableReferenceExpression(OUTPUT_INTERFACE_FIELD_NAME)));

// Wrap FeatureTearDown:
// var testWorkerId = <testRunner>.TestWorkerId;
// <FeatureTearDown>
// XUnitParallelWorkerTracker.Instance.ReleaseWorker(testWorkerId);
generationContext.TestClassCleanupMethod.Statements.Insert(0,
new CodeVariableDeclarationStatement(typeof(string), "testWorkerId",
new CodePropertyReferenceExpression(new CodeVariableReferenceExpression(generationContext.TestRunnerField.Name), "TestWorkerId")));
generationContext.TestClassCleanupMethod.Statements.Add(
new CodeMethodInvokeExpression(
new CodeVariableReferenceExpression(GlobalNamespaceIfCSharp(XUNITPARALLELWORKERTRACKER_INSTANCE)),
"ReleaseWorker",
new CodeVariableReferenceExpression("testWorkerId")));
}

protected virtual void IgnoreFeature(TestClassGenerationContext generationContext)
Expand Down Expand Up @@ -414,14 +400,6 @@ public void MarkCodeMethodInvokeExpressionAsAwait(CodeMethodInvokeExpression exp
CodeDomHelper.MarkCodeMethodInvokeExpressionAsAwait(expression);
}

public CodeExpression GetTestWorkerIdExpression()
{
// XUnitParallelWorkerTracker.Instance.GetWorkerId()
return new CodeMethodInvokeExpression(
new CodeVariableReferenceExpression(GlobalNamespaceIfCSharp(XUNITPARALLELWORKERTRACKER_INSTANCE)),
"GetWorkerId");
}

private string GlobalNamespaceIfCSharp(string typeName)
{
return CodeDomHelper.TargetLanguage == CodeDomProviderLanguage.CSharp ? "global::" + typeName : typeName;
Expand Down
2 changes: 1 addition & 1 deletion Reqnroll/ISyncTestRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Reqnroll
public interface ISyncTestRunner
{
/// <summary>
/// The ID of the parallel test worker processing the current scenario. How the worker ID is obtained is dependent on the test execution framework.
/// The ID of the parallel test worker processing the current scenario.
/// </summary>
string TestWorkerId { get; }

Expand Down
4 changes: 3 additions & 1 deletion Reqnroll/ITestRunner.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
using System;
using System.Threading.Tasks;

namespace Reqnroll
{
public interface ITestRunner
{
/// <summary>
/// The ID of the parallel test worker processing the current scenario. How the worker ID is obtained is dependent on the test execution framework.
/// The ID of the parallel test worker processing the current scenario.
/// </summary>
string TestWorkerId { get; }
gasparnagy marked this conversation as resolved.
Show resolved Hide resolved
FeatureContext FeatureContext { get; }
ScenarioContext ScenarioContext { get; }
ITestThreadContext TestThreadContext { get; }

[Obsolete("TestWorkerId is now managed by Reqnroll internally - Method will be removed in v3")]
obligaron marked this conversation as resolved.
Show resolved Hide resolved
void InitializeTestRunner(string testWorkerId);
gasparnagy marked this conversation as resolved.
Show resolved Hide resolved

Task OnTestRunStartAsync();
Expand Down
3 changes: 2 additions & 1 deletion Reqnroll/ITestRunnerManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ public interface ITestRunnerManager
Assembly TestAssembly { get; }
Assembly[] BindingAssemblies { get; }
bool IsMultiThreaded { get; }
ITestRunner GetTestRunner(string workerId);
ITestRunner GetTestRunner();
void ReleaseTestThreadContext(ITestThreadContext testThreadContext);
gasparnagy marked this conversation as resolved.
Show resolved Hide resolved
void Initialize(Assembly testAssembly);
Task FireTestRunEndAsync();
Task FireTestRunStartAsync();
Expand Down
2 changes: 1 addition & 1 deletion Reqnroll/Infrastructure/ContainerBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public virtual IObjectContainer CreateScenarioContainer(IObjectContainer testThr
return scenarioContainer;
}

public IObjectContainer CreateFeatureContainer(IObjectContainer testThreadContainer, FeatureInfo featureInfo)
public virtual IObjectContainer CreateFeatureContainer(IObjectContainer testThreadContainer, FeatureInfo featureInfo)
{
if (testThreadContainer == null)
throw new ArgumentNullException(nameof(testThreadContainer));
Expand Down
21 changes: 21 additions & 0 deletions Reqnroll/Infrastructure/TestThreadContainerInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Reqnroll.BoDi;

namespace Reqnroll.Infrastructure;

internal class TestThreadContainerInfo
{
internal string Id { get; }

internal TestThreadContainerInfo(string id)
{
Id = id;
}

internal static string GetId(IObjectContainer objectContainer)
{
if (!objectContainer.IsRegistered<TestThreadContainerInfo>())
return null;
var testThreadContainerInfo = objectContainer.Resolve<TestThreadContainerInfo>();
return testThreadContainerInfo.Id;
}
}
6 changes: 4 additions & 2 deletions Reqnroll/TestRunner.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Threading.Tasks;
using Reqnroll.Bindings;
using Reqnroll.Infrastructure;
Expand All @@ -8,7 +9,7 @@ public class TestRunner : ITestRunner
{
private readonly ITestExecutionEngine _executionEngine;

public string TestWorkerId { get; private set; }
public string TestWorkerId => TestThreadContainerInfo.GetId(TestThreadContext.TestThreadContainer);

public TestRunner(ITestExecutionEngine executionEngine)
{
Expand All @@ -26,9 +27,10 @@ public async Task OnTestRunStartAsync()
await _executionEngine.OnTestRunStartAsync();
}

[Obsolete("TestWorkerId is now managed by Reqnroll internally - Method will be removed in v3")]
public void InitializeTestRunner(string testWorkerId)
{
TestWorkerId = testWorkerId;
// do nothing method will be removed
}

public async Task OnFeatureStartAsync(FeatureInfo featureInfo)
Expand Down
Loading