diff --git a/TestFx.sln b/TestFx.sln index efe419e3a9..b89806055c 100644 --- a/TestFx.sln +++ b/TestFx.sln @@ -184,6 +184,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TimeoutTestProject", "test\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DeploymentTestProjectNetCore", "test\E2ETests\TestAssets\DeploymentTestProjectNetCore\DeploymentTestProjectNetCore.csproj", "{26F0B8EF-92D4-4A23-ACB4-D1B662F0EEBE}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TimeoutTestProjectNetCore", "test\E2ETests\TestAssets\TimeoutTestProjectNetCore\TimeoutTestProjectNetCore.csproj", "{ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution src\TestFramework\Extension.Shared\Extension.Shared.projitems*{272ca5e1-8e81-4825-9e47-86cce02f700d}*SharedItemsImports = 13 @@ -1116,6 +1118,30 @@ Global {26F0B8EF-92D4-4A23-ACB4-D1B662F0EEBE}.Release|x64.Build.0 = Release|Any CPU {26F0B8EF-92D4-4A23-ACB4-D1B662F0EEBE}.Release|x86.ActiveCfg = Release|Any CPU {26F0B8EF-92D4-4A23-ACB4-D1B662F0EEBE}.Release|x86.Build.0 = Release|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Code Analysis Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Code Analysis Debug|Any CPU.Build.0 = Debug|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Code Analysis Debug|ARM.ActiveCfg = Debug|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Code Analysis Debug|ARM.Build.0 = Debug|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Code Analysis Debug|x64.ActiveCfg = Debug|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Code Analysis Debug|x64.Build.0 = Debug|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Code Analysis Debug|x86.ActiveCfg = Debug|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Code Analysis Debug|x86.Build.0 = Debug|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Debug|ARM.ActiveCfg = Debug|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Debug|ARM.Build.0 = Debug|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Debug|x64.ActiveCfg = Debug|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Debug|x64.Build.0 = Debug|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Debug|x86.ActiveCfg = Debug|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Debug|x86.Build.0 = Debug|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Release|Any CPU.Build.0 = Release|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Release|ARM.ActiveCfg = Release|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Release|ARM.Build.0 = Release|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Release|x64.ActiveCfg = Release|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Release|x64.Build.0 = Release|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Release|x86.ActiveCfg = Release|Any CPU + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1178,6 +1204,7 @@ Global {7FB80AAB-7123-4416-B6CD-8D3D69AA83F1} = {D53BD452-F69F-4FB3-8B98-386EDA28A4C8} {4F0B2ACF-1341-42AF-918C-669A6D5CEA2B} = {D53BD452-F69F-4FB3-8B98-386EDA28A4C8} {26F0B8EF-92D4-4A23-ACB4-D1B662F0EEBE} = {D53BD452-F69F-4FB3-8B98-386EDA28A4C8} + {ED27A844-6870-4FE6-8FEF-3ABDD1ED6564} = {D53BD452-F69F-4FB3-8B98-386EDA28A4C8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {31E0F4D5-975A-41CC-933E-545B2201FAF9} diff --git a/src/Adapter/PlatformServices.NetCore/Services/NetCoreTestContextImplementation.cs b/src/Adapter/PlatformServices.NetCore/Services/NetCoreTestContextImplementation.cs index 62aaa28ceb..26011945cd 100644 --- a/src/Adapter/PlatformServices.NetCore/Services/NetCoreTestContextImplementation.cs +++ b/src/Adapter/PlatformServices.NetCore/Services/NetCoreTestContextImplementation.cs @@ -10,7 +10,7 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; - + using System.Threading; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ObjectModel; @@ -67,6 +67,7 @@ public TestContextImplementation(ITestMethod testMethod, StringWriter writer, ID this.stringWriter = writer; this.InitializeProperties(); this.testResultFiles = new List(); + this.CancellationTokenSource = new CancellationTokenSource(); } #region TestContext impl diff --git a/src/Adapter/PlatformServices.Shared/netstandard1.0/Services/ns10ThreadOperations.cs b/src/Adapter/PlatformServices.Shared/netstandard1.0/Services/ns10ThreadOperations.cs index cb2f8f18b3..53b9960cb9 100644 --- a/src/Adapter/PlatformServices.Shared/netstandard1.0/Services/ns10ThreadOperations.cs +++ b/src/Adapter/PlatformServices.Shared/netstandard1.0/Services/ns10ThreadOperations.cs @@ -26,13 +26,21 @@ public class ThreadOperations : IThreadOperations public bool Execute(Action action, int timeout, CancellationToken cancelToken) { var executionTask = Task.Factory.StartNew(action); - if (executionTask.Wait(timeout, cancelToken)) + try { - return true; + if (executionTask.Wait(timeout, cancelToken)) + { + return true; + } + else + { + // Timed out. + return false; + } } - else + catch (OperationCanceledException) { - // Timed out. + // Task execution cancelled. return false; } } diff --git a/test/E2ETests/Smoke.E2E.Tests/TimeoutTests.cs b/test/E2ETests/Smoke.E2E.Tests/TimeoutTests.cs index f11e87c08d..b325537948 100644 --- a/test/E2ETests/Smoke.E2E.Tests/TimeoutTests.cs +++ b/test/E2ETests/Smoke.E2E.Tests/TimeoutTests.cs @@ -11,25 +11,39 @@ namespace MSTestAdapter.Smoke.E2ETests public class TimeoutTests : CLITestBase { private const string TimeoutTestAssembly = "TimeoutTestProject.dll"; + private const string TimeoutTestAssemblyNetCore = "netcoreapp1.1\\TimeoutTestProjectNetCore.dll"; private const int TestMethodWaitTimeInMs = 6000; private const int OverheadTimeInMs = 2500; + private const string TimeoutFileToValidateNetCore = "netcoreapp1.1\\TimeoutTestOutputNetCore.txt"; + private const string TimeoutFileToValidate = "TimeoutTestOutput.txt"; [TestMethod] public void ValidateTimeoutTests() { - this.InvokeVsTestForExecution(new string[] { TimeoutTestAssembly }); + this.Validate(TimeoutTestAssembly, TimeoutFileToValidate); + } + + [TestMethod] + public void ValidateTimeoutTestsNetCore() + { + this.Validate(TimeoutTestAssemblyNetCore, TimeoutFileToValidateNetCore); + } + + private void Validate(string testAssembly, string fileToValidate) + { + this.InvokeVsTestForExecution(new string[] { testAssembly }); this.ValidateTestRunTime(TestMethodWaitTimeInMs + OverheadTimeInMs); this.ValidateFailedTestsCount(2); this.ValidateFailedTestsContain( - TimeoutTestAssembly, + testAssembly, false, "TimeoutTestProject.TerimnateLongRunningTasksUsingTokenTestClass.TerimnateLongRunningTasksUsingToken", "TimeoutTestProject.SelfTerminatingTestClass.SelfTerminatingTestMethod"); - Assert.IsTrue(File.Exists(this.GetAssetFullPath("TimeoutTestOutput.txt")), "Unable to locate the TimeoutTestOutput.txt file"); + Assert.IsTrue(File.Exists(this.GetAssetFullPath(fileToValidate)), "Unable to locate the TimeoutTestOutput.txt file"); } } } diff --git a/test/E2ETests/TestAssets/TimeoutTestProjectNetCore/SelfTerminatingTestClass.cs b/test/E2ETests/TestAssets/TimeoutTestProjectNetCore/SelfTerminatingTestClass.cs new file mode 100644 index 0000000000..9945962493 --- /dev/null +++ b/test/E2ETests/TestAssets/TimeoutTestProjectNetCore/SelfTerminatingTestClass.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace TimeoutTestProject +{ + [TestClass] + public class SelfTerminatingTestClass + { + public TestContext TestContext { get; set; } + + [TestMethod] + [Timeout(60000)] + public void SelfTerminatingTestMethod() + { + TestContext.CancellationTokenSource.Cancel(); + } + } +} diff --git a/test/E2ETests/TestAssets/TimeoutTestProjectNetCore/TerimnateLongRunningTasksUsingTokenTestClass.cs b/test/E2ETests/TestAssets/TimeoutTestProjectNetCore/TerimnateLongRunningTasksUsingTokenTestClass.cs new file mode 100644 index 0000000000..2147c35b66 --- /dev/null +++ b/test/E2ETests/TestAssets/TimeoutTestProjectNetCore/TerimnateLongRunningTasksUsingTokenTestClass.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace TimeoutTestProject +{ + [TestClass] + public class TerimnateLongRunningTasksUsingTokenTestClass + { + public TestContext TestContext { get; set; } + + [TestMethod] + [Timeout(5000)] + public void TerimnateLongRunningTasksUsingToken() + { + var longTask = new Thread(ExecuteLong); + longTask.Start(); + longTask.Join(); + } + + private void ExecuteLong() + { + try + { + File.Delete("TimeoutTestOutputNetCore.txt"); + Task.Delay(100000).Wait(TestContext.CancellationTokenSource.Token); + } + catch (OperationCanceledException) + { + File.WriteAllText("TimeoutTestOutputNetCore.txt", "Written from long running thread post termination"); + } + } + } +} diff --git a/test/E2ETests/TestAssets/TimeoutTestProjectNetCore/TimeoutTestProjectNetCore.csproj b/test/E2ETests/TestAssets/TimeoutTestProjectNetCore/TimeoutTestProjectNetCore.csproj new file mode 100644 index 0000000000..fbebb3b499 --- /dev/null +++ b/test/E2ETests/TestAssets/TimeoutTestProjectNetCore/TimeoutTestProjectNetCore.csproj @@ -0,0 +1,22 @@ + + + ..\..\..\..\ + + + + netcoreapp1.1 + NetCore + false + + $(TestFxRoot)artifacts\TestAssets\ + + + + + + + + + + +