diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/NativeAotTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/NativeAotTests.cs index 51063b1c8b..711840bcd4 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/NativeAotTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/NativeAotTests.cs @@ -9,8 +9,11 @@ namespace MSTest.Acceptance.IntegrationTests; [TestClass] public class NativeAotTests : AcceptanceTestBase { + // Source code for a project that validates MSTest supporting Native AOT. + // Because MSTest is built on top of Microsoft.Testing.Platform, this also exercises + // additional MTP code paths beyond what the MTP-only NativeAOT test covers. private const string SourceCode = """ -#file NativeAotTests.csproj +#file MSTestNativeAotTests.csproj $TargetFramework$ @@ -20,6 +23,8 @@ public class NativeAotTests : AcceptanceTestBase true preview true + + false @@ -41,7 +46,7 @@ public class NativeAotTests : AcceptanceTestBase using Microsoft.Testing.Platform.Extensions.Messages; using Microsoft.Testing.Platform.Extensions.TestFramework; -using NativeAotTests; +using MSTestNativeAotTests; ITestApplicationBuilder builder = await TestApplication.CreateBuilderAsync(args); builder.AddTestFramework(new SourceGeneratedTestNodesBuilder()); @@ -84,13 +89,14 @@ public void TestMethod3(int a, int b) [TestMethod] // The hosted AzDO agents for Mac OS don't have the required tooling for us to test Native AOT. [OSCondition(ConditionMode.Exclude, OperatingSystems.OSX)] - public async Task NativeAotTests_WillRunWithExitCodeZero() + [DynamicData(nameof(TargetFrameworks.NetForDynamicData), typeof(TargetFrameworks))] + public async Task NativeAotTests_WillRunWithExitCodeZero(string tfm) { using TestAsset generator = await TestAsset.GenerateAssetAsync( - "NativeAotTests", + $"MSTestNativeAotTests_{tfm}", SourceCode .PatchCodeWithReplace("$MicrosoftTestingPlatformVersion$", MicrosoftTestingPlatformVersion) - .PatchCodeWithReplace("$TargetFramework$", TargetFrameworks.NetCurrent) + .PatchCodeWithReplace("$TargetFramework$", tfm) .PatchCodeWithReplace("$MSTestVersion$", MSTestVersion) .PatchCodeWithReplace("$MSTestEngineVersion$", MSTestEngineVersion), addPublicFeeds: true); @@ -101,13 +107,13 @@ await DotnetCli.RunAsync( retryCount: 0, cancellationToken: TestContext.CancellationToken); DotnetMuxerResult compilationResult = await DotnetCli.RunAsync( - $"publish {generator.TargetAssetPath} -r {RID}", + $"publish {generator.TargetAssetPath} -r {RID} -f {tfm}", AcceptanceFixture.NuGetGlobalPackagesFolder.Path, retryCount: 0, cancellationToken: TestContext.CancellationToken); compilationResult.AssertOutputContains("Generating native code"); - var testHost = TestHost.LocateFrom(generator.TargetAssetPath, "NativeAotTests", TargetFrameworks.NetCurrent, RID, Verb.publish); + var testHost = TestHost.LocateFrom(generator.TargetAssetPath, "MSTestNativeAotTests", tfm, RID, Verb.publish); TestHostResult result = await testHost.ExecuteAsync(cancellationToken: TestContext.CancellationToken); result.AssertOutputContains($"MSTest.Engine v{MSTestEngineVersion}"); diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/SdkTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/SdkTests.cs index 2b694ed400..b86d008f09 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/SdkTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/SdkTests.cs @@ -291,25 +291,25 @@ public async Task Invalid_TestingProfile_Name_Should_Fail(string multiTfm, Build } [TestMethod] - [OSCondition(OperatingSystems.Windows)] - public async Task NativeAot_Smoke_Test_Windows() + [OSCondition(ConditionMode.Exclude, OperatingSystems.OSX)] + public async Task NativeAot_Smoke_Test() { using TestAsset testAsset = await TestAsset.GenerateAssetAsync( AssetName, SingleTestSourceCode .PatchCodeWithReplace("$MSTestVersion$", MSTestVersion) - // temporarily set test to be on net10.0 as older TFMs are broken until https://github.com/dotnet/runtime/pull/115951 is serviced. .PatchCodeWithReplace("$TargetFramework$", TargetFrameworks.NetCurrent) .PatchCodeWithReplace("$ExtraProperties$", """ true false + + false """), addPublicFeeds: true); DotnetMuxerResult compilationResult = await DotnetCli.RunAsync( $"publish -r {RID} -f {TargetFrameworks.NetCurrent} {testAsset.TargetAssetPath}", AcceptanceFixture.NuGetGlobalPackagesFolder.Path, - // We prefer to use the outer retry mechanism as we need some extra checks retryCount: 0, cancellationToken: TestContext.CancellationToken); compilationResult.AssertOutputContains("Generating native code"); diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/TrimTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/TrimTests.cs new file mode 100644 index 0000000000..0226b15693 --- /dev/null +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/TrimTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Testing.Platform.Acceptance.IntegrationTests; + +namespace MSTest.Acceptance.IntegrationTests; + +[TestClass] +public class TrimTests : AcceptanceTestBase +{ + // Source code for a minimal project that deeply validates trim/AOT compatibility of + // MSTest assemblies by using TrimmerRootAssembly to force the trimmer to analyze + // all code paths in each assembly, not just those reachable from the test entry point. + // See https://learn.microsoft.com/dotnet/core/deploying/trimming/prepare-libraries-for-trimming + private const string TrimAnalysisSourceCode = """ +#file MSTestTrimAnalysisTest.csproj + + + $TargetFramework$ + Exe + true + + false + + + + + + + + + + + + + +#file Program.cs +System.Console.WriteLine("This project validates trim/AOT compatibility via dotnet publish."); +"""; + + [TestMethod] + [DynamicData(nameof(TargetFrameworks.NetForDynamicData), typeof(TargetFrameworks))] + public async Task Publish_ShouldNotProduceTrimWarnings(string tfm) + { + // See https://github.com/microsoft/testfx/issues/7153 + // This test forces deep trim analysis of MSTest assemblies using TrimmerRootAssembly + // to catch trim warnings that would not be caught by only testing reachable code paths. + using TestAsset generator = await TestAsset.GenerateAssetAsync( + $"MSTestTrimAnalysisTest_{tfm}", + TrimAnalysisSourceCode + .PatchCodeWithReplace("$MicrosoftTestingPlatformVersion$", MicrosoftTestingPlatformVersion) + .PatchCodeWithReplace("$MSTestVersion$", MSTestVersion) + .PatchCodeWithReplace("$MSTestEngineVersion$", MSTestEngineVersion) + .PatchCodeWithReplace("$TargetFramework$", tfm), + addPublicFeeds: true); + + await DotnetCli.RunAsync( + $"restore {generator.TargetAssetPath} -r {RID}", + AcceptanceFixture.NuGetGlobalPackagesFolder.Path, + retryCount: 0, + cancellationToken: TestContext.CancellationToken); + await DotnetCli.RunAsync( + $"publish {generator.TargetAssetPath} -r {RID} -f {tfm}", + AcceptanceFixture.NuGetGlobalPackagesFolder.Path, + retryCount: 0, + cancellationToken: TestContext.CancellationToken); + } + + public TestContext TestContext { get; set; } +} diff --git a/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/NativeAotTests.cs b/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/NativeAotTests.cs new file mode 100644 index 0000000000..3cd9100b23 --- /dev/null +++ b/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/NativeAotTests.cs @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.Testing.Platform.Acceptance.IntegrationTests; + +[TestClass] +public class NativeAotTests : AcceptanceTestBase +{ + // Source code for a minimal NativeAOT test project using a locally defined test framework + // (not MSTest) to validate that Microsoft.Testing.Platform itself supports Native AOT. + private const string SourceCode = """ +#file NativeAotTests.csproj + + + $TargetFramework$ + enable + enable + Exe + true + preview + true + + false + + + + + + +#file Program.cs +using Microsoft.Testing.Platform.Builder; +using Microsoft.Testing.Platform.Capabilities.TestFramework; +using Microsoft.Testing.Platform.Extensions.Messages; +using Microsoft.Testing.Platform.Extensions.TestFramework; + +ITestApplicationBuilder builder = await TestApplication.CreateBuilderAsync(args); +builder.RegisterTestFramework(_ => new TestFrameworkCapabilities(), (_, __) => new DummyTestFramework()); +using ITestApplication app = await builder.BuildAsync(); +return await app.RunAsync(); + +internal class DummyTestFramework : ITestFramework, IDataProducer +{ + public string Uid => nameof(DummyTestFramework); + + public string Version => "1.0.0"; + + public string DisplayName => nameof(DummyTestFramework); + + public string Description => nameof(DummyTestFramework); + + public Task IsEnabledAsync() => Task.FromResult(true); + + public Type[] DataTypesProduced => new[] { typeof(TestNodeUpdateMessage) }; + + public Task CreateTestSessionAsync(CreateTestSessionContext context) + => Task.FromResult(new CreateTestSessionResult() { IsSuccess = true }); + + public Task CloseTestSessionAsync(CloseTestSessionContext context) + => Task.FromResult(new CloseTestSessionResult() { IsSuccess = true }); + + public async Task ExecuteRequestAsync(ExecuteRequestContext context) + { + await context.MessageBus.PublishAsync(this, new TestNodeUpdateMessage(context.Request.Session.SessionUid, new TestNode() + { + Uid = "Test1", + DisplayName = "Test1", + Properties = new PropertyBag(PassedTestNodeStateProperty.CachedInstance), + })); + + context.Complete(); + } +} +"""; + + [TestMethod] + // The hosted AzDO agents for Mac OS don't have the required tooling for us to test Native AOT. + [OSCondition(ConditionMode.Exclude, OperatingSystems.OSX)] + [DynamicData(nameof(TargetFrameworks.NetForDynamicData), typeof(TargetFrameworks))] + public async Task NativeAotTests_WillRunWithExitCodeZero(string tfm) + { + using TestAsset generator = await TestAsset.GenerateAssetAsync( + $"NativeAotTests_{tfm}", + SourceCode + .PatchCodeWithReplace("$MicrosoftTestingPlatformVersion$", MicrosoftTestingPlatformVersion) + .PatchCodeWithReplace("$TargetFramework$", tfm), + addPublicFeeds: true); + + await DotnetCli.RunAsync( + $"restore {generator.TargetAssetPath} -r {RID}", + AcceptanceFixture.NuGetGlobalPackagesFolder.Path, + retryCount: 0, + cancellationToken: TestContext.CancellationToken); + DotnetMuxerResult compilationResult = await DotnetCli.RunAsync( + $"publish {generator.TargetAssetPath} -r {RID} -f {tfm}", + AcceptanceFixture.NuGetGlobalPackagesFolder.Path, + retryCount: 0, + cancellationToken: TestContext.CancellationToken); + compilationResult.AssertOutputContains("Generating native code"); + + var testHost = TestInfrastructure.TestHost.LocateFrom(generator.TargetAssetPath, "NativeAotTests", tfm, RID, Verb.publish); + + TestHostResult result = await testHost.ExecuteAsync(cancellationToken: TestContext.CancellationToken); + result.AssertExitCodeIs(0); + } + + public TestContext TestContext { get; set; } +} diff --git a/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/TrimTests.cs b/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/TrimTests.cs new file mode 100644 index 0000000000..d936e81f5e --- /dev/null +++ b/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/TrimTests.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.Testing.Platform.Acceptance.IntegrationTests; + +[TestClass] +public class TrimTests : AcceptanceTestBase +{ + // Source code for a minimal project that deeply validates trim/AOT compatibility of + // Microsoft.Testing.Platform by using TrimmerRootAssembly to force the trimmer to analyze + // all code paths in the assembly, not just those reachable from the test entry point. + // See https://learn.microsoft.com/dotnet/core/deploying/trimming/prepare-libraries-for-trimming + private const string TrimAnalysisSourceCode = """ +#file TrimAnalysisTest.csproj + + + $TargetFramework$ + Exe + true + + false + + + + + + + + + + +#file Program.cs +System.Console.WriteLine("This project validates trim/AOT compatibility via dotnet publish."); +"""; + + [TestMethod] + [DynamicData(nameof(TargetFrameworks.NetForDynamicData), typeof(TargetFrameworks))] + public async Task Publish_ShouldNotProduceTrimWarnings(string tfm) + { + // See https://github.com/microsoft/testfx/issues/7153 + // This test forces deep trim analysis of Microsoft.Testing.Platform using TrimmerRootAssembly + // to catch trim warnings that would not be caught by only testing reachable code paths. + using TestAsset generator = await TestAsset.GenerateAssetAsync( + $"TrimAnalysisTest_{tfm}", + TrimAnalysisSourceCode + .PatchCodeWithReplace("$MicrosoftTestingPlatformVersion$", MicrosoftTestingPlatformVersion) + .PatchCodeWithReplace("$TargetFramework$", tfm), + addPublicFeeds: true); + + await DotnetCli.RunAsync( + $"restore {generator.TargetAssetPath} -r {RID}", + AcceptanceFixture.NuGetGlobalPackagesFolder.Path, + retryCount: 0, + cancellationToken: TestContext.CancellationToken); + await DotnetCli.RunAsync( + $"publish {generator.TargetAssetPath} -r {RID} -f {tfm}", + AcceptanceFixture.NuGetGlobalPackagesFolder.Path, + retryCount: 0, + cancellationToken: TestContext.CancellationToken); + } + + public TestContext TestContext { get; set; } +}