diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleProcessManager.cs b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleProcessManager.cs
index 8cbd290e01..56b3f041cd 100644
--- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleProcessManager.cs
+++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleProcessManager.cs
@@ -9,10 +9,10 @@ namespace Microsoft.TestPlatform.VsTestConsole.TranslationLayer
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces;
using System;
- using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
+ using System.Threading;
using Resources = Microsoft.VisualStudio.TestPlatform.VsTestConsole.TranslationLayer.Resources.Resources;
///
@@ -39,6 +39,11 @@ internal class VsTestConsoleProcessManager : IProcessManager
///
private const string DIAG_ARGUMENT = "/diag:{0};tracelevel={1}";
+ ///
+ /// EndSession timeout
+ ///
+ private const int ENDSESSIONTIMEOUT = 1000;
+
private string vstestConsolePath;
private object syncObject = new object();
private bool vstestConsoleStarted = false;
@@ -46,6 +51,7 @@ internal class VsTestConsoleProcessManager : IProcessManager
private readonly bool isNetCoreRunner;
private string dotnetExePath;
private Process process;
+ private ManualResetEvent processExitedEvent = new ManualResetEvent(false);
internal IFileHelper FileHelper { get; set; }
@@ -143,15 +149,16 @@ public void StartProcess(ConsoleParameters consoleParameters)
public void ShutdownProcess()
{
// Ideally process should die by itself
- if (IsProcessInitialized())
+ if(!processExitedEvent.WaitOne(ENDSESSIONTIMEOUT) && IsProcessInitialized())
{
+ EqtTrace.Info($"VsTestConsoleProcessManager.ShutDownProcess : Terminating vstest.console process after waiting for {ENDSESSIONTIMEOUT} milliseconds.");
vstestConsoleExited = true;
this.process.OutputDataReceived -= Process_OutputDataReceived;
this.process.ErrorDataReceived -= Process_ErrorDataReceived;
SafelyTerminateProcess();
this.process.Dispose();
this.process = null;
- }
+ }
}
private void SafelyTerminateProcess()
@@ -173,8 +180,8 @@ private void Process_Exited(object sender, EventArgs e)
{
lock (syncObject)
{
- ShutdownProcess();
-
+ processExitedEvent.Set();
+ vstestConsoleExited = true;
this.ProcessExited?.Invoke(sender, e);
}
}
diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleWrapper.cs b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleWrapper.cs
index f340ef50e3..e947ea8617 100644
--- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleWrapper.cs
+++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleWrapper.cs
@@ -258,6 +258,10 @@ public void EndSession()
{
this.requestSender.EndSession();
this.requestSender.Close();
+
+ // If vstest.console is still hanging around, it should be explicitly killed.
+ this.vstestConsoleProcessManager.ShutdownProcess();
+
this.sessionStarted = false;
}
diff --git a/test/Microsoft.TestPlatform.AcceptanceTests/TranslationLayerTests/RunTests.cs b/test/Microsoft.TestPlatform.AcceptanceTests/TranslationLayerTests/RunTests.cs
index cc3082edb2..ad155994c5 100644
--- a/test/Microsoft.TestPlatform.AcceptanceTests/TranslationLayerTests/RunTests.cs
+++ b/test/Microsoft.TestPlatform.AcceptanceTests/TranslationLayerTests/RunTests.cs
@@ -11,6 +11,7 @@ namespace Microsoft.TestPlatform.AcceptanceTests.TranslationLayerTests
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
+ using System.Diagnostics;
using System.Linq;
using VisualStudio.TestPlatform.ObjectModel.Logging;
@@ -52,6 +53,25 @@ public void RunAllTests(RunnerInfo runnerInfo)
Assert.AreEqual(2, this.runEventHandler.TestResults.Count(t => t.Outcome == TestOutcome.Skipped));
}
+ [TestMethod]
+ [NetFullTargetFrameworkDataSource]
+ [NetCoreTargetFrameworkDataSource]
+ public void EndSessionShouldEnsureVstestConsoleProcessDies(RunnerInfo runnerInfo)
+ {
+ var numOfProcesses = Process.GetProcessesByName("vstest.console").Length;
+
+ AcceptanceTestBase.SetTestEnvironment(this.testEnvironment, runnerInfo);
+ this.Setup();
+
+ this.vstestConsoleWrapper.RunTests(this.GetTestAssemblies(), this.GetDefaultRunSettings(), this.runEventHandler);
+ this.vstestConsoleWrapper?.EndSession();
+
+ // Assert
+ Assert.AreEqual(numOfProcesses, Process.GetProcessesByName("vstest.console").Length);
+
+ this.vstestConsoleWrapper = null;
+ }
+
[TestMethod]
[NetFullTargetFrameworkDataSource]
[NetCoreTargetFrameworkDataSource]
diff --git a/test/TranslationLayer.UnitTests/VsTestConsoleWrapperTests.cs b/test/TranslationLayer.UnitTests/VsTestConsoleWrapperTests.cs
index e9c89892d0..2691bb43c7 100644
--- a/test/TranslationLayer.UnitTests/VsTestConsoleWrapperTests.cs
+++ b/test/TranslationLayer.UnitTests/VsTestConsoleWrapperTests.cs
@@ -310,6 +310,7 @@ public void EndSessionShouldSucceed()
this.mockRequestSender.Verify(rs => rs.EndSession(), Times.Once);
this.mockRequestSender.Verify(rs => rs.Close(), Times.Once);
+ this.mockProcessManager.Verify(x => x.ShutdownProcess(), Times.Once);
}
}
}