Skip to content

Commit

Permalink
Early testhost startup performance work (#2584)
Browse files Browse the repository at this point in the history
  • Loading branch information
cvpoienaru authored Dec 11, 2020
1 parent 269dcaa commit 70abd63
Show file tree
Hide file tree
Showing 90 changed files with 6,319 additions and 1,347 deletions.
87 changes: 80 additions & 7 deletions src/Microsoft.TestPlatform.Client/DesignMode/DesignModeClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ namespace Microsoft.VisualStudio.TestPlatform.Client.DesignMode
using System.Net;
using System.Threading;
using System.Threading.Tasks;

using Microsoft.VisualStudio.TestPlatform.Client;
using Microsoft.VisualStudio.TestPlatform.Client.TestRunAttachmentsProcessing;
using Microsoft.VisualStudio.TestPlatform.Client.RequestHelper;
using Microsoft.VisualStudio.TestPlatform.Common.Logging;
Expand All @@ -17,11 +19,14 @@ namespace Microsoft.VisualStudio.TestPlatform.Client.DesignMode
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces;
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers;
using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Payloads;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces;

using CommunicationUtilitiesResources = CommunicationUtilities.Resources.Resources;

/// <summary>
Expand All @@ -32,7 +37,7 @@ public class DesignModeClient : IDesignModeClient
private readonly ICommunicationManager communicationManager;
private readonly IDataSerializer dataSerializer;

private ProtocolConfig protocolConfig = Constants.DefaultProtocolConfig;
private ProtocolConfig protocolConfig = ObjectModel.Constants.DefaultProtocolConfig;
private IEnvironment platformEnvironment;
private TestSessionMessageLogger testSessionMessageLogger;
private object lockObject = new object();
Expand Down Expand Up @@ -170,6 +175,20 @@ private void ProcessRequests(ITestRequestManager testRequestManager)
break;
}

case MessageType.StartTestSession:
{
var testSessionPayload = this.communicationManager.DeserializePayload<StartTestSessionPayload>(message);
this.StartTestSession(testSessionPayload, testRequestManager);
break;
}

case MessageType.StopTestSession:
{
var testSessionInfo = this.communicationManager.DeserializePayload<TestSessionInfo>(message);
this.StopTestSession(testSessionInfo);
break;
}

case MessageType.StartDiscovery:
{
var discoveryPayload = this.dataSerializer.DeserializePayload<DiscoveryRequestPayload>(message);
Expand All @@ -183,7 +202,7 @@ private void ProcessRequests(ITestRequestManager testRequestManager)
var testRunPayload =
this.communicationManager.DeserializePayload<TestRunRequestPayload>(
message);
this.StartTestRun(testRunPayload, testRequestManager, skipTestHostLaunch: true);
this.StartTestRun(testRunPayload, testRequestManager, shouldLaunchTesthost: true);
break;
}

Expand All @@ -193,7 +212,7 @@ private void ProcessRequests(ITestRequestManager testRequestManager)
var testRunPayload =
this.communicationManager.DeserializePayload<TestRunRequestPayload>(
message);
this.StartTestRun(testRunPayload, testRequestManager, skipTestHostLaunch: false);
this.StartTestRun(testRunPayload, testRequestManager, shouldLaunchTesthost: false);
break;
}

Expand Down Expand Up @@ -322,7 +341,7 @@ public bool AttachDebuggerToProcess(int pid, CancellationToken cancellationToken
// If an attach request is issued but there is no support for attaching on the other
// side of the communication channel, we simply return and let the caller know the
// request failed.
if (this.protocolConfig.Version < Constants.MinimumProtocolVersionWithDebugSupport)
if (this.protocolConfig.Version < ObjectModel.Constants.MinimumProtocolVersionWithDebugSupport)
{
return false;
}
Expand Down Expand Up @@ -408,7 +427,7 @@ public void TestRunMessageHandler(object sender, TestRunMessageEventArgs e)
}
}

private void StartTestRun(TestRunRequestPayload testRunPayload, ITestRequestManager testRequestManager, bool skipTestHostLaunch)
private void StartTestRun(TestRunRequestPayload testRunPayload, ITestRequestManager testRequestManager, bool shouldLaunchTesthost)
{
Task.Run(
() =>
Expand All @@ -417,8 +436,15 @@ private void StartTestRun(TestRunRequestPayload testRunPayload, ITestRequestMana
{
testRequestManager.ResetOptions();

var customLauncher = skipTestHostLaunch ?
DesignModeTestHostLauncherFactory.GetCustomHostLauncherForTestRun(this, testRunPayload) : null;
// We must avoid re-launching the test host if the test run payload already
// contains test session info. Test session info being present is an indicative
// of an already running test host spawned by a start test session call.
var customLauncher =
shouldLaunchTesthost && testRunPayload.TestSessionInfo == null
? DesignModeTestHostLauncherFactory.GetCustomHostLauncherForTestRun(
this,
testRunPayload.DebuggingEnabled)
: null;

testRequestManager.RunTests(testRunPayload, customLauncher, new DesignModeTestEventsRegistrar(this), this.protocolConfig);
}
Expand Down Expand Up @@ -497,6 +523,53 @@ private void StartTestRunAttachmentsProcessing(TestRunAttachmentsProcessingPaylo
});
}

private void StartTestSession(StartTestSessionPayload payload, ITestRequestManager requestManager)
{
Task.Run(() =>
{
var eventsHandler = new TestSessionEventsHandler(this.communicationManager);

try
{
var customLauncher = payload.HasCustomHostLauncher
? DesignModeTestHostLauncherFactory.GetCustomHostLauncherForTestRun(this, payload.IsDebuggingEnabled)
: null;

requestManager.ResetOptions();
requestManager.StartTestSession(payload, customLauncher, eventsHandler, this.protocolConfig);
}
catch (Exception ex)
{
EqtTrace.Error("DesignModeClient: Exception in StartTestSession: " + ex);

eventsHandler.HandleLogMessage(TestMessageLevel.Error, ex.ToString());
eventsHandler.HandleStartTestSessionComplete(null);
}
});
}

private void StopTestSession(TestSessionInfo testSessionInfo)
{
Task.Run(() =>
{
var eventsHandler = new TestSessionEventsHandler(this.communicationManager);

try
{
var stopped = TestSessionPool.Instance.KillSession(testSessionInfo);

eventsHandler.HandleStopTestSessionComplete(testSessionInfo, stopped);
}
catch (Exception ex)
{
EqtTrace.Error("DesignModeClient: Exception in StopTestSession: " + ex);

eventsHandler.HandleLogMessage(TestMessageLevel.Error, ex.ToString());
eventsHandler.HandleStopTestSessionComplete(testSessionInfo, false);
}
});
}

#region IDisposable Support

private bool disposedValue = false; // To detect redundant calls
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ public static class DesignModeTestHostLauncherFactory
private static ITestHostLauncher defaultLauncher;
private static ITestHostLauncher debugLauncher;

public static ITestHostLauncher GetCustomHostLauncherForTestRun(IDesignModeClient designModeClient, TestRunRequestPayload testRunRequestPayload)
public static ITestHostLauncher GetCustomHostLauncherForTestRun(IDesignModeClient designModeClient, bool debuggingEnabled)
{
ITestHostLauncher testHostLauncher = null;

if (!testRunRequestPayload.DebuggingEnabled)
if (!debuggingEnabled)
{
testHostLauncher = defaultLauncher = defaultLauncher ?? new DesignModeTestHostLauncher(designModeClient);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,69 +5,105 @@ namespace Microsoft.VisualStudio.TestPlatform.Client.RequestHelper
{
using System;
using System.Collections.Generic;

using Microsoft.VisualStudio.TestPlatform.Client;
using Microsoft.VisualStudio.TestPlatform.Common.Interfaces;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Payloads;

/// <summary>
/// Defines the contract that command line
/// Defines the contract for running various requests.
/// </summary>
public interface ITestRequestManager : IDisposable
{
/// <summary>
/// Initializes the extensions while probing additional paths
/// Initializes the extensions while probing additional paths.
/// </summary>
/// <param name="pathToAdditionalExtensions">Paths to Additional extensions</param>
/// <param name="skipExtensionFilters">Skip extension filtering by name (if true)</param>
void InitializeExtensions(IEnumerable<string> pathToAdditionalExtensions, bool skipExtensionFilters);
///
/// <param name="pathToAdditionalExtensions">Paths to additional extensions.</param>
/// <param name="skipExtensionFilters">Skip extension filtering by name if true.</param>
void InitializeExtensions(
IEnumerable<string> pathToAdditionalExtensions,
bool skipExtensionFilters);

/// <summary>
/// Resets Vstest.console.exe Options
/// Resets vstest.console.exe options.
/// </summary>
void ResetOptions();

/// <summary>
/// Discover Tests given a list of sources, runsettings
/// Discovers tests given a list of sources and some run settings.
/// </summary>
///
/// <param name="discoveryPayload">Discovery payload.</param>
/// <param name="disoveryEventsRegistrar">Discovery events registrar.</param>
/// <param name="protocolConfig">Protocol related information.</param>
void DiscoverTests(
DiscoveryRequestPayload discoveryPayload,
ITestDiscoveryEventsRegistrar disoveryEventsRegistrar,
ProtocolConfig protocolConfig);

/// <summary>
/// Runs tests given a list of sources and some run settings.
/// </summary>
/// <param name="discoveryPayload">Discovery payload</param>
/// <param name="disoveryEventsRegistrar">Discovery events registrar - registers and unregisters discovery events</param>
/// <param name="protocolConfig">Protocol related information</param>
void DiscoverTests(DiscoveryRequestPayload discoveryPayload, ITestDiscoveryEventsRegistrar disoveryEventsRegistrar, ProtocolConfig protocolConfig);
///
/// <param name="testRunRequestPayLoad">Test run request payload.</param>
/// <param name="customTestHostLauncher">Custom test host launcher for the run.</param>
/// <param name="testRunEventsRegistrar">Run events registrar.</param>
/// <param name="protocolConfig">Protocol related information.</param>
void RunTests(
TestRunRequestPayload testRunRequestPayLoad,
ITestHostLauncher customTestHostLauncher,
ITestRunEventsRegistrar testRunEventsRegistrar,
ProtocolConfig protocolConfig);

/// <summary>
/// Run Tests with given a test of sources
/// Processes test run attachments.
/// </summary>
/// <param name="testRunRequestPayLoad">Test Run Request payload</param>
/// <param name="customTestHostLauncher">Custom testHostLauncher for the run</param>
/// <param name="testRunEventsRegistrar">RunEvents registrar</param>
/// <param name="protocolConfig">Protocol related information</param>
void RunTests(TestRunRequestPayload testRunRequestPayLoad, ITestHostLauncher customTestHostLauncher, ITestRunEventsRegistrar testRunEventsRegistrar, ProtocolConfig protocolConfig);
///
/// <param name="testRunAttachmentsProcessingPayload">
/// Test run attachments processing payload.
/// </param>
/// <param name="testRunAttachmentsProcessingEventsHandler">
/// Test run attachments processing events handler.
/// </param>
/// <param name="protocolConfig">Protocol related information.</param>
void ProcessTestRunAttachments(
TestRunAttachmentsProcessingPayload testRunAttachmentsProcessingPayload,
ITestRunAttachmentsProcessingEventsHandler testRunAttachmentsProcessingEventsHandler,
ProtocolConfig protocolConfig);

/// <summary>
/// Processes test run attachments
/// Starts a test session.
/// </summary>
/// <param name="testRunAttachmentsProcessingPayload">Test run attachments processing payload</param>
/// <param name="testRunAttachmentsProcessingEventsHandler">Test run attachments processing events handler</param>
void ProcessTestRunAttachments(TestRunAttachmentsProcessingPayload testRunAttachmentsProcessingPayload, ITestRunAttachmentsProcessingEventsHandler testRunAttachmentsProcessingEventsHandler, ProtocolConfig protocolConfig);
///
/// <param name="payload">The start test session payload.</param>
/// <param name="testHostLauncher">The custom test host launcher.</param>
/// <param name="eventsHandler">The events handler.</param>
/// <param name="protocolConfig">Protocol related information.</param>
void StartTestSession(
StartTestSessionPayload payload,
ITestHostLauncher testHostLauncher,
ITestSessionEventsHandler eventsHandler,
ProtocolConfig protocolConfig);

/// <summary>
/// Cancel the current TestRun request
/// Cancel the current test run request.
/// </summary>
void CancelTestRun();

/// <summary>
/// Abort the current TestRun
/// Abort the current test run.
/// </summary>
void AbortTestRun();

/// <summary>
/// Cancels the current discovery request
/// Cancels the current discovery request.
/// </summary>
void CancelDiscovery();

/// <summary>
/// Cancels the current test run attachments processing request
/// Cancels the current test run attachments processing request.
/// </summary>
void CancelTestRunAttachmentsProcessing();
}
Expand Down
Loading

0 comments on commit 70abd63

Please sign in to comment.