Skip to content

[Test Optimization] Add support for MSTest 3.9.x #7070

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

Merged
merged 7 commits into from
Jun 6, 2025
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
84 changes: 24 additions & 60 deletions tracer/build/PackageVersionsLatestMajors.g.props

Large diffs are not rendered by default.

352 changes: 140 additions & 212 deletions tracer/build/PackageVersionsLatestMinors.g.props

Large diffs are not rendered by default.

102 changes: 24 additions & 78 deletions tracer/build/PackageVersionsLatestSpecific.g.props

Large diffs are not rendered by default.

172 changes: 172 additions & 0 deletions tracer/build/supported_calltargets.g.json
Original file line number Diff line number Diff line change
Expand Up @@ -9949,6 +9949,31 @@
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "MsTestV2",
"AssemblyName": "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter",
"TargetTypeName": "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestAssemblyInfo",
"TargetMethodName": "RunAssemblyInitialize",
"TargetReturnType": "System.Void",
"TargetParameterTypes": [
"Microsoft.VisualStudio.TestTools.UnitTesting.TestContext",
"_"
],
"MinimumVersion": {
"Item1": 14,
"Item2": 0,
"Item3": 0
},
"MaximumVersion": {
"Item1": 14,
"Item2": 65535,
"Item3": 65535
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.Testing.MsTestV2.TestAssemblyInfoRunAssemblyInitializeIntegrationV3_9",
"IntegrationKind": 0,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "MsTestV2",
"AssemblyName": "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter",
Expand All @@ -9971,6 +9996,31 @@
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "MsTestV2",
"AssemblyName": "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter",
"TargetTypeName": "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo",
"TargetMethodName": "ExecuteClassCleanup",
"TargetReturnType": "_",
"TargetParameterTypes": [
"_",
"_"
],
"MinimumVersion": {
"Item1": 14,
"Item2": 0,
"Item3": 0
},
"MaximumVersion": {
"Item1": 14,
"Item2": 65535,
"Item3": 65535
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.Testing.MsTestV2.TestClassInfoExecuteClassCleanupIntegrationV3_9",
"IntegrationKind": 0,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "MsTestV2",
"AssemblyName": "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter",
Expand Down Expand Up @@ -10043,6 +10093,31 @@
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "MsTestV2",
"AssemblyName": "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter",
"TargetTypeName": "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestClassInfo",
"TargetMethodName": "RunClassInitialize",
"TargetReturnType": "System.Void",
"TargetParameterTypes": [
"_",
"_"
],
"MinimumVersion": {
"Item1": 14,
"Item2": 0,
"Item3": 0
},
"MaximumVersion": {
"Item1": 14,
"Item2": 65535,
"Item3": 65535
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.Testing.MsTestV2.TestClassInfoRunClassInitializeIntegrationV3_9",
"IntegrationKind": 0,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "MsTestV2",
"AssemblyName": "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter",
Expand Down Expand Up @@ -10111,6 +10186,30 @@
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "MsTestV2",
"AssemblyName": "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter",
"TargetTypeName": "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodRunner",
"TargetMethodName": "ExecuteTestAsync",
"TargetReturnType": "System.Threading.Tasks.Task`1[Microsoft.VisualStudio.TestTools.UnitTesting.TestResult[]]",
"TargetParameterTypes": [
"Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo"
],
"MinimumVersion": {
"Item1": 14,
"Item2": 0,
"Item3": 0
},
"MaximumVersion": {
"Item1": 14,
"Item2": 65535,
"Item3": 65535
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.Testing.MsTestV2.TestMethodRunnerExecuteTestIntegrationV3_9",
"IntegrationKind": 0,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "MsTestV2",
"AssemblyName": "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter",
Expand All @@ -10137,6 +10236,31 @@
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "MsTestV2",
"AssemblyName": "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter",
"TargetTypeName": "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TypeCache",
"TargetMethodName": "GetTestMethodInfo",
"TargetReturnType": "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo",
"TargetParameterTypes": [
"Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.TestMethod",
"Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ITestContext"
],
"MinimumVersion": {
"Item1": 14,
"Item2": 0,
"Item3": 0
},
"MaximumVersion": {
"Item1": 14,
"Item2": 65535,
"Item3": 65535
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.Testing.MsTestV2.TypeCacheGetTestMethodInfoIntegrationV3_9",
"IntegrationKind": 0,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "MsTestV2",
"AssemblyName": "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter",
Expand Down Expand Up @@ -10312,6 +10436,54 @@
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "MsTestV2",
"AssemblyName": "Microsoft.VisualStudio.TestPlatform.TestFramework",
"TargetTypeName": "Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute",
"TargetMethodName": "ExecuteAsync",
"TargetReturnType": "System.Threading.Tasks.Task`1[Microsoft.VisualStudio.TestTools.UnitTesting.TestResult[]]",
"TargetParameterTypes": [
"Microsoft.VisualStudio.TestTools.UnitTesting.ITestMethod"
],
"MinimumVersion": {
"Item1": 14,
"Item2": 0,
"Item3": 0
},
"MaximumVersion": {
"Item1": 14,
"Item2": 65535,
"Item3": 65535
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.Testing.MsTestV2.TestMethodAttributeExecuteAsyncIntegration",
"IntegrationKind": 0,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "MsTestV2",
"AssemblyName": "Microsoft.VisualStudio.TestPlatform.TestFramework",
"TargetTypeName": "Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute",
"TargetMethodName": "ExecuteAsync",
"TargetReturnType": "System.Threading.Tasks.Task`1[Microsoft.VisualStudio.TestTools.UnitTesting.TestResult[]]",
"TargetParameterTypes": [
"Microsoft.VisualStudio.TestTools.UnitTesting.ITestMethod"
],
"MinimumVersion": {
"Item1": 14,
"Item2": 0,
"Item3": 0
},
"MaximumVersion": {
"Item1": 14,
"Item2": 65535,
"Item3": 65535
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.Testing.MsTestV2.TestMethodAttributeExecuteAsyncIntegration",
"IntegrationKind": 1,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "MySql",
"AssemblyName": "MySql.Data",
Expand Down
4 changes: 2 additions & 2 deletions tracer/build/supported_versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -920,8 +920,8 @@
"minVersionAvailableInclusive": "1.1.11",
"minVersionSupportedInclusive": "1.1.11",
"minVersionTestedInclusive": null,
"maxVersionSupportedInclusive": "3.8.3",
"maxVersionAvailableInclusive": "3.8.3",
"maxVersionSupportedInclusive": "3.9.1",
"maxVersionAvailableInclusive": "3.9.1",
"maxVersionTestedInclusive": null
}
]
Expand Down
4 changes: 2 additions & 2 deletions tracer/dependabot/Datadog.Dependabot.Integrations.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@

<!-- Integration: Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter -->
<!-- Assembly: Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter -->
<!-- Latest package https://www.nuget.org/packages/MSTest.TestAdapter/3.8.3 -->
<PackageReference Include="MSTest.TestAdapter" Version="3.8.3" />
<!-- Latest package https://www.nuget.org/packages/MSTest.TestAdapter/3.9.1 -->
<PackageReference Include="MSTest.TestAdapter" Version="3.9.1" />

<!-- Integration: MySql.Data -->
<!-- Assembly: MySql.Data -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,27 @@ namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.Testing.MsTestV2;
/// <summary>
/// TestMethodInfo ducktype interface
/// </summary>
internal interface ITestMethodInfo : ITestMethod
internal interface ITestMethodInfo : ITestMethodInfoWithParent
{
/// <summary>
/// Gets the test method options
/// </summary>
ITestMethodOptions? TestMethodOptions { get; }
}

/// <summary>
/// TestMethodInfo (v3_9) ducktype interface
/// </summary>
internal interface ITestMethodInfoV3_9 : ITestMethodInfoWithParent
{
/// <summary>
/// Gets or sets the test executor.
/// </summary>
object? Executor { get; set; }
}

internal interface ITestMethodInfoWithParent : ITestMethod
{
/// <summary>
/// Gets the parent class Info object.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,15 @@ internal interface ITestMethodRunner
[DuckField(Name = "testMethodInfo,_testMethodInfo")]
ITestMethodInfo? TestMethodInfo { get; }
}

/// <summary>
/// TestMethodRunner (v3_9) ducktype interface
/// </summary>
internal interface ITestMethodRunnerV3_9
{
/// <summary>
/// Gets the TestMethodInfo instance
/// </summary>
[DuckField(Name = "testMethodInfo,_testMethodInfo")]
ITestMethodInfoV3_9? TestMethodInfo { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ internal static class MsTestIntegration
["b754cc51-34ed-419c-8582-bff04c3db05f"] = "3.8.0",
["2b3d62e3-5607-4ebd-840e-ee80475cc0bc"] = "3.8.1",
["3fe23123-93a2-4c44-8219-0a5f27a10316"] = "3.8.2",
["102f7a9d-d61b-4864-b3c7-0a097a85f47b"] = "3.9.0",
["e7bba6ac-32f6-4e62-9a3a-cf259c9e7448"] = "3.9.1",
};

private static long _totalTestCases;
Expand All @@ -90,12 +92,11 @@ internal static class MsTestIntegration
internal static Test? OnMethodBegin<TTestMethod>(TTestMethod testMethodInstance, Type type, bool isRetry, DateTimeOffset? startDate = null)
where TTestMethod : ITestMethod
{
Common.Log.Debug("{Value}", Environment.StackTrace);
var testMethod = testMethodInstance.MethodInfo;
var testName = testMethodInstance.TestMethodName ?? string.Empty;

var suite = TestSuite.Current;
if (suite is null && testMethodInstance.Instance.TryDuckCast<ITestMethodInfo>(out var testMethodInfo))
if (suite is null && testMethodInstance.Instance.TryDuckCast<ITestMethodInfoWithParent>(out var testMethodInfo))
{
suite = GetOrCreateTestSuiteFromTestClassInfo(testMethodInfo.Parent);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@

using System;
using System.Reflection;
using System.Threading.Tasks;
using Datadog.Trace.Ci;
using Datadog.Trace.DuckTyping;

namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.Testing.MsTestV2;

internal class SkipTestMethodExecutor
internal abstract class SkipTestMethodExecutor
{
private readonly object _arrayInstance;
private readonly string _skipReason;

public SkipTestMethodExecutor(Assembly assembly, string skipReason)
protected SkipTestMethodExecutor(Assembly assembly, string skipReason)
{
var testResultType = assembly.GetType("Microsoft.VisualStudio.TestTools.UnitTesting.TestResult", throwOnError: true)!;
var array = Array.CreateInstance(testResultType, 1);
Expand All @@ -31,16 +32,46 @@ public SkipTestMethodExecutor(Assembly assembly, string skipReason)
_skipReason = skipReason;
}

[DuckReverseMethod(Name = "Execute", ParameterTypeNames = ["Microsoft.VisualStudio.TestTools.UnitTesting.ITestMethod"])]
public object Execute(object testMethod)
protected void ProcessTestMethod(object testMethod)
{
if (testMethod.TryDuckCast<ITestMethod>(out var testMethodInfo))
{
// Create the skip span
MsTestIntegration.OnMethodBegin(testMethodInfo, testMethod.GetType(), isRetry: false)?
.Close(TestStatus.Skip, TimeSpan.Zero, _skipReason);
}
}

internal class SyncImpl(Assembly assembly, string skipReason) : SkipTestMethodExecutor(assembly, skipReason)
{
[DuckReverseMethod(Name = "Execute", ParameterTypeNames = ["Microsoft.VisualStudio.TestTools.UnitTesting.ITestMethod"])]
public object Execute(object testMethod)
{
ProcessTestMethod(testMethod);
return _arrayInstance;
}
}

internal class AsyncImpl(Assembly assembly, string skipReason) : SkipTestMethodExecutor(assembly, skipReason)
{
private object? _resultInstance;

return _arrayInstance;
[DuckReverseMethod(Name = "ExecuteAsync", ParameterTypeNames = ["Microsoft.VisualStudio.TestTools.UnitTesting.ITestMethod"])]
public object Execute(object testMethod)
{
ProcessTestMethod(testMethod);
_resultInstance ??= ((TaskTestResultArray?)Activator.CreateInstance(typeof(TaskTestResultArray<>).MakeGenericType([_arrayInstance.GetType()]), _arrayInstance))!.Result;
return _resultInstance;
}

private abstract class TaskTestResultArray
{
public abstract object Result { get; }
}

private class TaskTestResultArray<T>(T value) : TaskTestResultArray
{
public override object Result { get; } = Task.FromResult(value);
}
}
}
Loading
Loading