Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testhost sharing between discovery & execution #2687

Merged
merged 32 commits into from
Nov 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
cad90d0
Groundwork for testhost sharing
cvpoienaru Jan 11, 2021
859965e
Enabled test session info passing through TP
cvpoienaru Jan 11, 2021
30775f1
Testhost sharing is working
cvpoienaru Jan 12, 2021
b9057db
Fixed double channel close
cvpoienaru Jan 14, 2021
bd267b7
Fixed not logging test platform event source when request is successful
cvpoienaru Jan 15, 2021
03c5c96
Merge branch 'master' into copoiena/tp-testhost-sharing
cvpoienaru Jan 15, 2021
80059ae
Added logic to avoid testhost cleanup
cvpoienaru Jan 18, 2021
809d6f4
Using console wrapper instead of test session
cvpoienaru Jan 19, 2021
b831d87
Reverted to previous interface
cvpoienaru Jan 22, 2021
8ebaabc
Removed trailing whitespaces after restoring previous interface
cvpoienaru Jan 25, 2021
ff8507b
Reverted whitespaces
cvpoienaru Jan 25, 2021
629f20f
Reverted whitespaces 2
cvpoienaru Jan 25, 2021
f91228e
Added check for matching run settings and disabled test sessions with…
cvpoienaru Jan 25, 2021
3c2e26b
Refactored SetupChannel
cvpoienaru Jan 25, 2021
ef039a2
Implemented a disposable TestSession
cvpoienaru Jan 27, 2021
38df898
Merge branch 'master' into copoiena/tp-testhost-sharing
cvpoienaru Jan 29, 2021
55118ac
Merge branch 'main' into copoiena/tp-testhost-sharing
cvpoienaru Aug 31, 2021
3e43177
Checked out loc changes from main
cvpoienaru Aug 31, 2021
b3953b0
Adjusted the number of testhosts to be spawned
cvpoienaru Sep 8, 2021
58fd909
Fixed test container to test host association
cvpoienaru Sep 16, 2021
0c533f5
Merge branch 'main' into copoiena/tp-testhost-sharing
cvpoienaru Sep 16, 2021
90170c5
Fixed public API errors
cvpoienaru Sep 16, 2021
6328248
Fixed unit tests
cvpoienaru Sep 16, 2021
73fe5d0
Added more unit tests
cvpoienaru Oct 20, 2021
7a89d9a
Merge branch 'main' into copoiena/tp-testhost-sharing
cvpoienaru Oct 20, 2021
9cfd6bf
Fixed public API
cvpoienaru Oct 20, 2021
4b246a8
Added more tests
cvpoienaru Oct 25, 2021
a64fd37
Added more tests
cvpoienaru Oct 25, 2021
b80b578
Added Obsolete attributes to mark the API isn't final
cvpoienaru Nov 4, 2021
02d6205
Fixed code review comments
cvpoienaru Nov 12, 2021
6e75cfc
Merge branch 'main' into copoiena/tp-testhost-sharing
cvpoienaru Nov 12, 2021
393fb3e
Fixed review comments
cvpoienaru Nov 18, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 7 additions & 28 deletions src/Microsoft.TestPlatform.Client/TestPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public ITestRunRequest CreateTestRunRequest(
}

/// <inheritdoc/>
public void StartTestSession(
public bool StartTestSession(
cvpoienaru marked this conversation as resolved.
Show resolved Hide resolved
cvpoienaru marked this conversation as resolved.
Show resolved Hide resolved
IRequestData requestData,
StartTestSessionCriteria testSessionCriteria,
ITestSessionEventsHandler eventsHandler)
Expand All @@ -170,44 +170,23 @@ public void StartTestSession(
this.AddExtensionAssemblies(testSessionCriteria.RunSettings);

var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(testSessionCriteria.RunSettings);

// Update extension assemblies from source when design mode is false.
//
// TODO (copoiena): Is it possible for this code to run if we're not in design mode ?
// An use case for this would be when running tests with "dotnet test". Usually there's
// a build involved then.
if (!runConfiguration.DesignMode)
{
return;
}

// Initialize loggers.
var loggerManager = this.TestEngine.GetLoggerManager(requestData);
loggerManager.Initialize(testSessionCriteria.RunSettings);

var testHostManager = this.testHostProviderManager.GetTestHostManagerByRunConfiguration(testSessionCriteria.RunSettings);
ThrowExceptionIfTestHostManagerIsNull(testHostManager, testSessionCriteria.RunSettings);

testHostManager.Initialize(TestSessionMessageLogger.Instance, testSessionCriteria.RunSettings);

if (testSessionCriteria.TestHostLauncher != null)
{
testHostManager.SetCustomLauncher(testSessionCriteria.TestHostLauncher);
return false;
}

var testSessionManager = this.TestEngine.GetTestSessionManager(requestData, testHostManager, testSessionCriteria);
var testSessionManager = this.TestEngine.GetTestSessionManager(requestData, testSessionCriteria);
if (testSessionManager == null)
{
// The test session manager is null because the combination of runsettings and
// sources tells us we should run in-process (i.e. in vstest.console). Because
// of this no session will be created because there's no testhost to be launched.
// Expecting a subsequent call to execute tests with the same set of parameters.
eventsHandler.HandleStartTestSessionComplete(null);
cvpoienaru marked this conversation as resolved.
Show resolved Hide resolved
return;
return false;
}

testSessionManager.Initialize(false);
testSessionManager.StartSession(testSessionCriteria, eventsHandler);
return testSessionManager.StartSession(eventsHandler);
}

/// <summary>
Expand All @@ -234,11 +213,11 @@ public void ClearExtensions()

private void ThrowExceptionIfTestHostManagerIsNull(
ITestRuntimeProvider testHostManager,
string settingXml)
string settingsXml)
{
if (testHostManager == null)
{
EqtTrace.Error("TestPlatform.CreateTestRunRequest: No suitable testHostProvider found for runsettings : {0}", settingXml);
EqtTrace.Error("TestPlatform.CreateTestRunRequest: No suitable testHostProvider found for runsettings : {0}", settingsXml);
throw new TestPlatformException(string.Format(CultureInfo.CurrentCulture, ClientResources.NoTestHostProviderFound));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,22 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine
/// </summary>
public interface IProxyTestSessionManager
{
/// <summary>
/// Initialize the proxy.
/// </summary>
///
/// <param name="skipDefaultAdapters">Skip default adapters flag.</param>
void Initialize(bool skipDefaultAdapters);

/// <summary>
/// Starts the test session based on the test session criteria.
/// </summary>
///
/// <param name="criteria">The test session criteria.</param>
/// <param name="eventsHandler">
/// Event handler for handling events fired during test session management operations.
/// </param>
void StartSession(
StartTestSessionCriteria criteria,
ITestSessionEventsHandler eventsHandler);
///
/// <returns>True if the operation succeeded, false otherwise.</returns>
bool StartSession(ITestSessionEventsHandler eventsHandler);

/// <summary>
/// Stops the test session.
/// </summary>
void StopSession();
///
/// <returns>True if the operation succeeded, false otherwise.</returns>
bool StopSession();
cvpoienaru marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,13 @@ IProxyExecutionManager GetExecutionManager(
/// <param name="requestData">
/// The request data for providing test session services and data.
/// </param>
/// <param name="testHostManager">Test host manager for the current test session.</param>
/// <param name="testSessionCriteria">
/// Test session criteria of the current test session.
/// </param>
///
/// <returns>An IProxyTestSessionManager object that can manage test sessions.</returns>
IProxyTestSessionManager GetTestSessionManager(
IRequestData requestData,
ITestRuntimeProvider testHostManager,
StartTestSessionCriteria testSessionCriteria);

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ internal TestRequestSender(
{
}

public bool CloseConnectionOnOperationComplete { get; set; } = true;

/// <inheritdoc />
public int InitializeCommunication()
{
Expand Down Expand Up @@ -727,6 +729,16 @@ private bool IsOperationComplete()

private void SetOperationComplete()
{
// When sharing the testhost between discovery and execution we must keep the
// testhost alive after completing the operation it was spawned for. As such we
// suppress the test request sender channel close taking place here. This channel
// will be closed when the test session owner decides to dispose of the test session
// object.
if (!this.CloseConnectionOnOperationComplete)
cvpoienaru marked this conversation as resolved.
Show resolved Hide resolved
{
return;
}

// Complete the currently ongoing operation (Discovery/Execution)
if (EqtTrace.IsVerboseEnabled)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

using Microsoft.VisualStudio.TestPlatform.Common;
using Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework;
Expand All @@ -25,17 +26,43 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client
/// </summary>
public class ProxyDiscoveryManager : IProxyDiscoveryManager, IBaseProxy, ITestDiscoveryEventsHandler2
{
private ProxyOperationManager proxyOperationManager;
private readonly ITestRuntimeProvider testHostManager;
private IDataSerializer dataSerializer;
private bool isCommunicationEstablished;
private readonly TestSessionInfo testSessionInfo = null;
cvpoienaru marked this conversation as resolved.
Show resolved Hide resolved
Func<string, ProxyDiscoveryManager, ProxyOperationManager> proxyOperationManagerCreator;

private ITestRuntimeProvider testHostManager;
private IRequestData requestData;

private readonly IFileHelper fileHelper;
private readonly IDataSerializer dataSerializer;
private bool isCommunicationEstablished;

private ProxyOperationManager proxyOperationManager = null;
private ITestDiscoveryEventsHandler2 baseTestDiscoveryEventsHandler;
private bool skipDefaultAdapters;
private readonly IFileHelper fileHelper;

#region Constructors

/// <summary>
/// Initializes a new instance of the <see cref="ProxyDiscoveryManager"/> class.
/// </summary>
///
/// <param name="testSessionInfo">The test session info.</param>
/// <param name="proxyOperationManagerCreator">The proxy operation manager creator.</param>
public ProxyDiscoveryManager(
TestSessionInfo testSessionInfo,
Func<string, ProxyDiscoveryManager, ProxyOperationManager> proxyOperationManagerCreator)
{
// Filling in test session info and proxy information.
this.testSessionInfo = testSessionInfo;
this.proxyOperationManagerCreator = proxyOperationManagerCreator;

this.requestData = null;
this.testHostManager = null;
this.dataSerializer = JsonDataSerializer.Instance;
this.fileHelper = new FileHelper();
this.isCommunicationEstablished = false;
}

/// <summary>
/// Initializes a new instance of the <see cref="ProxyDiscoveryManager"/> class.
/// </summary>
Expand All @@ -55,9 +82,7 @@ public ProxyDiscoveryManager(
testHostManager,
JsonDataSerializer.Instance,
new FileHelper())
{
this.testHostManager = testHostManager;
}
{ }

/// <summary>
/// Initializes a new instance of the <see cref="ProxyDiscoveryManager"/> class.
Expand All @@ -81,11 +106,12 @@ internal ProxyDiscoveryManager(
IDataSerializer dataSerializer,
IFileHelper fileHelper)
{
this.dataSerializer = dataSerializer;
this.testHostManager = testHostManager;
this.isCommunicationEstablished = false;
this.requestData = requestData;
this.testHostManager = testHostManager;

this.dataSerializer = dataSerializer;
this.fileHelper = fileHelper;
this.isCommunicationEstablished = false;

// Create a new proxy operation manager.
this.proxyOperationManager = new ProxyOperationManager(requestData, requestSender, testHostManager, this);
Expand All @@ -104,6 +130,16 @@ public void Initialize(bool skipDefaultAdapters)
/// <inheritdoc/>
public void DiscoverTests(DiscoveryCriteria discoveryCriteria, ITestDiscoveryEventsHandler2 eventHandler)
{
if (this.proxyOperationManager == null)
{
this.proxyOperationManager = this.proxyOperationManagerCreator(
discoveryCriteria.Sources.First(),
this);

this.testHostManager = this.proxyOperationManager.TestHostManager;
this.requestData = this.proxyOperationManager.RequestData;
}

this.baseTestDiscoveryEventsHandler = eventHandler;
try
{
Expand Down Expand Up @@ -149,6 +185,12 @@ public void DiscoverTests(DiscoveryCriteria discoveryCriteria, ITestDiscoveryEve
/// <inheritdoc/>
public void Abort()
{
// Do nothing if the proxy is not initialized yet.
if (this.proxyOperationManager == null)
{
return;
}

// Cancel fast, try to stop testhost deployment/launch
this.proxyOperationManager.CancellationTokenSource.Cancel();
this.Close();
Expand All @@ -157,7 +199,25 @@ public void Abort()
/// <inheritdoc/>
public void Close()
{
this.proxyOperationManager.Close();
// Do nothing if the proxy is not initialized yet.
if (this.proxyOperationManager == null)
{
return;
}

// When no test session is being used we don't share the testhost
// between test discovery and test run. The testhost is closed upon
// successfully completing the operation it was spawned for.
//
// In contrast, the new workflow (using test sessions) means we should keep
// the testhost alive until explicitly closed by the test session owner.
if (this.testSessionInfo == null)
{
this.proxyOperationManager.Close();
return;
}

TestSessionPool.Instance.ReturnProxy(this.testSessionInfo, this.proxyOperationManager.Id);
}

/// <inheritdoc/>
Expand Down
Loading