diff --git a/Directory.Build.targets b/Directory.Build.targets
index f0c700ee2e..6d96423635 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -4,7 +4,18 @@
<_NetFrameworkHostedCompilersVersion Condition="'$(_NetFrameworkHostedCompilersVersion)' == ''">4.11.0-3.24280.3
-
+
+
+ $(DefineConstants);IS_VSTEST_REPO
+
+ $(MSBuildWarningsAsMessages);MSB3277
+
+
diff --git a/eng/Versions.props b/eng/Versions.props
index 65d997fd1f..f3ef3e1262 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -70,7 +70,7 @@
<_MicrosoftVSSDKBuildToolsVersion_>17.14.2119
5.0.0
13.0.3
- 9.0.11
+ 10.0.0
4.5.5
8.0.0
18.0.0-preview-1-10911-061
diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Microsoft.TestPlatform.CoreUtilities.csproj b/src/Microsoft.TestPlatform.CoreUtilities/Microsoft.TestPlatform.CoreUtilities.csproj
index 866225a77c..6776a4de05 100644
--- a/src/Microsoft.TestPlatform.CoreUtilities/Microsoft.TestPlatform.CoreUtilities.csproj
+++ b/src/Microsoft.TestPlatform.CoreUtilities/Microsoft.TestPlatform.CoreUtilities.csproj
@@ -19,6 +19,7 @@
+
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj b/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj
index 1675d4cb00..0d20b23a19 100644
--- a/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj
+++ b/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj
@@ -37,6 +37,7 @@
+
diff --git a/src/datacollector/app.config b/src/datacollector/app.config
index d464fe4c5d..3b5c8143b9 100644
--- a/src/datacollector/app.config
+++ b/src/datacollector/app.config
@@ -22,11 +22,21 @@
-
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/src/package/Microsoft.TestPlatform.CLI/Microsoft.TestPlatform.CLI.csproj b/src/package/Microsoft.TestPlatform.CLI/Microsoft.TestPlatform.CLI.csproj
index 696cb68cbf..f3ad7825d0 100644
--- a/src/package/Microsoft.TestPlatform.CLI/Microsoft.TestPlatform.CLI.csproj
+++ b/src/package/Microsoft.TestPlatform.CLI/Microsoft.TestPlatform.CLI.csproj
@@ -37,7 +37,7 @@
Sometimes NU1702 is not suppressed correctly, so force reducing severity of the warning.
See https://github.com/NuGet/Home/issues/9147
-->
- NU1702
+ $(MSBuildWarningsAsMessages);NU1702
diff --git a/src/package/Microsoft.TestPlatform.Portable/Microsoft.TestPlatform.Portable.csproj b/src/package/Microsoft.TestPlatform.Portable/Microsoft.TestPlatform.Portable.csproj
index 33fde7df1b..f17f680575 100644
--- a/src/package/Microsoft.TestPlatform.Portable/Microsoft.TestPlatform.Portable.csproj
+++ b/src/package/Microsoft.TestPlatform.Portable/Microsoft.TestPlatform.Portable.csproj
@@ -12,7 +12,7 @@
Sometimes NU1702 is not suppressed correctly, so force reducing severity of the warning.
See https://github.com/NuGet/Home/issues/9147
-->
- NU1702
+ $(MSBuildWarningsAsMessages);NU1702
diff --git a/src/package/Microsoft.TestPlatform/Microsoft.TestPlatform.csproj b/src/package/Microsoft.TestPlatform/Microsoft.TestPlatform.csproj
index 540e0910ea..6739984bbd 100644
--- a/src/package/Microsoft.TestPlatform/Microsoft.TestPlatform.csproj
+++ b/src/package/Microsoft.TestPlatform/Microsoft.TestPlatform.csproj
@@ -11,7 +11,7 @@
Sometimes NU1702 is not suppressed correctly, so force reducing severity of the warning.
See https://github.com/NuGet/Home/issues/9147
-->
- NU1702;NETSDK1023
+ $(MSBuildWarningsAsMessages);NU1702;NETSDK1023
diff --git a/src/testhost.x86/app.config b/src/testhost.x86/app.config
index ff5d13c675..84cb676f80 100644
--- a/src/testhost.x86/app.config
+++ b/src/testhost.x86/app.config
@@ -35,11 +35,21 @@
-
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/src/vstest.console/app.config b/src/vstest.console/app.config
index 115518cc51..de2fe51c34 100644
--- a/src/vstest.console/app.config
+++ b/src/vstest.console/app.config
@@ -27,11 +27,11 @@
-
+
-
+
@@ -40,7 +40,12 @@
-
+
+
+
+
+
+
@@ -55,7 +60,7 @@
-
+
diff --git a/test/Microsoft.TestPlatform.Acceptance.IntegrationTests/DiscoveryTests.cs b/test/Microsoft.TestPlatform.Acceptance.IntegrationTests/DiscoveryTests.cs
index 3680b3c9bc..ef1817aeb7 100644
--- a/test/Microsoft.TestPlatform.Acceptance.IntegrationTests/DiscoveryTests.cs
+++ b/test/Microsoft.TestPlatform.Acceptance.IntegrationTests/DiscoveryTests.cs
@@ -6,6 +6,7 @@
using System.IO;
using System.Linq;
using System.Reflection;
+using System.Runtime.Loader;
using Microsoft.TestPlatform.TestUtilities;
using Microsoft.VisualStudio.TestPlatform.Common.Utilities;
@@ -106,15 +107,37 @@ public void TypesToLoadAttributeTests()
}
};
- foreach (var extension in extensionsToVerify.Keys)
+ // Use a custom AssemblyLoadContext so that dependencies (e.g. SCI 10.0.0)
+ // resolve from the extensions directory rather than the test host's runtime.
+ var parentDirectory = Path.GetDirectoryName(extensionsDirectory)!;
+ var alc = new AssemblyLoadContext("ExtensionTest", isCollectible: true);
+ alc.Resolving += (context, name) =>
{
- var assemblyFile = Path.Combine(extensionsDirectory, extension);
- var assembly = Assembly.LoadFrom(assemblyFile);
+ var path = Path.Combine(extensionsDirectory, name.Name + ".dll");
+ if (File.Exists(path))
+ return context.LoadFromAssemblyPath(path);
+ path = Path.Combine(parentDirectory, name.Name + ".dll");
+ if (File.Exists(path))
+ return context.LoadFromAssemblyPath(path);
+ return null;
+ };
+
+ try
+ {
+ foreach (var extension in extensionsToVerify.Keys)
+ {
+ var assemblyFile = Path.Combine(extensionsDirectory, extension);
+ var assembly = alc.LoadFromAssemblyPath(assemblyFile);
- var expected = extensionsToVerify[extension];
- var actual = TypesToLoadUtilities.GetTypesToLoad(assembly).Select(i => i.FullName).ToArray();
+ var expected = extensionsToVerify[extension];
+ var actual = TypesToLoadUtilities.GetTypesToLoad(assembly).Select(i => i.FullName).ToArray();
- CollectionAssert.AreEquivalent(expected, actual, $"Specified types using TypesToLoadAttribute in \"{extension}\" assembly doesn't match the expected.");
+ CollectionAssert.AreEquivalent(expected, actual, $"Specified types using TypesToLoadAttribute in \"{extension}\" assembly doesn't match the expected.");
+ }
+ }
+ finally
+ {
+ alc.Unload();
}
}
diff --git a/test/Microsoft.TestPlatform.Acceptance.IntegrationTests/DistributedTestAgentScenarioTests.cs b/test/Microsoft.TestPlatform.Acceptance.IntegrationTests/DistributedTestAgentScenarioTests.cs
new file mode 100644
index 0000000000..972a6d6f2c
--- /dev/null
+++ b/test/Microsoft.TestPlatform.Acceptance.IntegrationTests/DistributedTestAgentScenarioTests.cs
@@ -0,0 +1,101 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Reflection.Metadata;
+using System.Reflection.PortableExecutable;
+
+using Microsoft.TestPlatform.TestUtilities;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Microsoft.TestPlatform.AcceptanceTests;
+
+///
+/// Tests that the DTA (Distributed Test Agent) scenario works: a .NET Framework host
+/// loads Microsoft.VisualStudio.TestPlatform.Common.dll without binding redirects. The shipped
+/// System.Collections.Immutable DLL must match the assembly version referenced by
+/// the compiled product assemblies.
+///
+[TestClass]
+public class DistributedTestAgentScenarioTests : AcceptanceTestBase
+{
+ ///
+ /// Validates that the Microsoft.TestPlatform nupkg layout (used by DTA/VSTest task)
+ /// contains a System.Collections.Immutable whose assembly version matches what
+ /// Common.dll was compiled against.
+ ///
+ [TestMethod]
+ public void NupkgLayout_CommonDll_CanLoadSciWithoutBindingRedirects()
+ {
+ var testPlatformDir = Path.Combine(
+ IntegrationTestEnvironment.PublishDirectory,
+ $"Microsoft.TestPlatform.{IntegrationTestEnvironment.LatestLocallyBuiltNugetVersion}.nupkg",
+ "tools", "net462", "Common7", "IDE", "Extensions", "TestPlatform");
+
+ ValidateDtaScenario(testPlatformDir, "nupkg");
+ }
+
+ ///
+ /// Validates that the V2.CLI VSIX layout also has matching SCI assembly versions.
+ ///
+ [TestMethod]
+ public void VsixLayout_CommonDll_CanLoadSciWithoutBindingRedirects()
+ {
+ var vsixDir = Path.GetDirectoryName(IntegrationTestEnvironment.LocalVsixInsertion);
+ if (vsixDir is null || !Directory.Exists(vsixDir))
+ {
+ Assert.Inconclusive("VSIX directory not found. Build with -pack to produce it.");
+ }
+
+ var vsixExtractDir = Path.Combine(IntegrationTestEnvironment.ArtifactsTempDirectory, "vsix-extracted");
+ if (!Directory.Exists(vsixExtractDir))
+ {
+ System.IO.Compression.ZipFile.ExtractToDirectory(IntegrationTestEnvironment.LocalVsixInsertion, vsixExtractDir);
+ }
+
+ ValidateDtaScenario(vsixExtractDir, "VSIX");
+ }
+
+ private static void ValidateDtaScenario(string testPlatformDir, string layoutName)
+ {
+ Assert.IsTrue(Directory.Exists(testPlatformDir), $"{layoutName} directory not found: {testPlatformDir}");
+
+ var commonDll = Path.Combine(testPlatformDir, "Microsoft.VisualStudio.TestPlatform.Common.dll");
+ var sciDll = Path.Combine(testPlatformDir, "System.Collections.Immutable.dll");
+
+ Assert.IsTrue(File.Exists(commonDll), $"Common.dll not found in {layoutName} layout: {commonDll}");
+ Assert.IsTrue(File.Exists(sciDll), $"System.Collections.Immutable.dll not found in {layoutName} layout: {sciDll}");
+
+ var sciVersion = System.Reflection.AssemblyName.GetAssemblyName(sciDll).Version;
+ var sciRefVersion = GetReferencedAssemblyVersion(commonDll, "System.Collections.Immutable");
+
+ Assert.IsNotNull(sciRefVersion, $"Common.dll in {layoutName} layout does not reference System.Collections.Immutable");
+
+ // For DTA scenario (no binding redirects), these MUST match exactly.
+ Assert.AreEqual(
+ sciRefVersion,
+ sciVersion,
+ $"{layoutName} layout: Common.dll references SCI {sciRefVersion} but shipped DLL is {sciVersion}. " +
+ $"DTA hosts without binding redirects will fail with FileLoadException.");
+ }
+
+ private static Version? GetReferencedAssemblyVersion(string assemblyPath, string referenceName)
+ {
+ using var stream = File.OpenRead(assemblyPath);
+ using var peReader = new PEReader(stream);
+ var mdReader = peReader.GetMetadataReader();
+ foreach (var handle in mdReader.AssemblyReferences)
+ {
+ var asmRef = mdReader.GetAssemblyReference(handle);
+ if (mdReader.GetString(asmRef.Name) == referenceName)
+ {
+ return asmRef.Version;
+ }
+ }
+
+ return null;
+ }
+}
+
diff --git a/test/TestAssets/DtaLikeHost/DtaLikeHost.csproj b/test/TestAssets/DtaLikeHost/DtaLikeHost.csproj
new file mode 100644
index 0000000000..cf11b4e281
--- /dev/null
+++ b/test/TestAssets/DtaLikeHost/DtaLikeHost.csproj
@@ -0,0 +1,71 @@
+
+
+
+
+
+ DtaLikeHost
+ net472
+ Exe
+
+ false
+ false
+ true
+
+ false
+ false
+
+
+
+
+
+
+
+
+ <_TestPlatformToolsDir>$(PkgMicrosoft_TestPlatform)\tools\net462\Common7\IDE\Extensions\TestPlatform
+
+
+
+
+ <_TestPlatformToolsDir>$(TestPlatformToolsDirOverride)
+
+
+
+
+
+ $(_TestPlatformToolsDir)\Microsoft.VisualStudio.TestPlatform.Common.dll
+ true
+
+
+ $(_TestPlatformToolsDir)\Microsoft.VisualStudio.TestPlatform.ObjectModel.dll
+ true
+
+
+
+
+
+
+
+
diff --git a/test/TestAssets/DtaLikeHost/Program.cs b/test/TestAssets/DtaLikeHost/Program.cs
new file mode 100644
index 0000000000..7999bed8a5
--- /dev/null
+++ b/test/TestAssets/DtaLikeHost/Program.cs
@@ -0,0 +1,53 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Reflection;
+
+using Microsoft.VisualStudio.TestPlatform.Common.Filtering;
+
+namespace DtaLikeHost;
+
+internal static class Program
+{
+ private static int Main()
+ {
+ // Report what Common.dll expects and what we ship next to it, so the mismatch
+ // (or agreement) is visible in the console output regardless of whether the
+ // CLR actually fails to bind.
+ var commonAsm = typeof(FilterExpressionWrapper).Assembly;
+ Console.WriteLine($"Common.dll path: {commonAsm.Location}");
+ Console.WriteLine($"Common.dll version: {commonAsm.GetName().Version}");
+ foreach (var r in commonAsm.GetReferencedAssemblies())
+ {
+ if (r.Name == "System.Collections.Immutable" || r.Name == "System.Reflection.Metadata")
+ {
+ Console.WriteLine($" Common.dll references {r.Name}, Version={r.Version}");
+ }
+ }
+
+ try
+ {
+ // A simple equality filter produces a FastFilter, which triggers
+ // FastFilter.Builder.ctor -> ImmutableDictionary.CreateBuilder(...)
+ // -> forces the CLR to resolve System.Collections.Immutable at the version
+ // baked into Common.dll's metadata.
+ var wrapper = new FilterExpressionWrapper("TestCategory=Foo");
+ Console.WriteLine($"FilterExpressionWrapper constructed: FilterString='{wrapper.FilterString}', ParseError='{wrapper.ParseError}'");
+
+ // Reflect on the private FastFilter field to prove it was actually built.
+ var fastFilterField = typeof(FilterExpressionWrapper).GetField("FastFilter", BindingFlags.Instance | BindingFlags.NonPublic);
+ var fastFilter = fastFilterField?.GetValue(wrapper);
+ Console.WriteLine($"FastFilter built: {fastFilter is not null}");
+ }
+ catch (Exception ex)
+ {
+ Console.Error.WriteLine("REPRO HIT: exception constructing FilterExpressionWrapper:");
+ Console.Error.WriteLine(ex);
+ return 1;
+ }
+
+ Console.WriteLine("OK - no binding exception.");
+ return 0;
+ }
+}