Skip to content

Fixed testhost crash for net7 #4112

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

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;

using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;

namespace Microsoft.VisualStudio.TestPlatform.Client;

internal class InProcessTestRunAttachmentsProcessingEventsHandler : ITestRunAttachmentsProcessingEventsHandler
{
private readonly ITestRunAttachmentsProcessingEventsHandler _eventsHandler;

public InProcessTestRunAttachmentsProcessingEventsHandler(
ITestRunAttachmentsProcessingEventsHandler eventsHandler)
{
_eventsHandler = eventsHandler;
}

public void HandleLogMessage(TestMessageLevel level, string? message)
{
_eventsHandler.HandleLogMessage(level, message);
}

public void HandleProcessedAttachmentsChunk(IEnumerable<AttachmentSet> attachments)
{
// Not implemented by design, keep in sync with the same named method from
// TestRunAttachmentsProcessingEventsHandler.cs.
throw new NotImplementedException();
}

public void HandleRawMessage(string rawMessage)
{
// No-op by design.
//
// For out-of-process vstest.console, raw messages are passed to the translation layer but
// they are never read and don't get passed to the actual events handler in TW. If they
// were (as it happens for in-process vstest.console since there is no more translation
// layer) a NotImplemented exception would be raised as per the time this of writing this
// note.
//
// Consider changing this logic in the future if TW changes the handling logic for raw
// messages.
}

public void HandleTestRunAttachmentsProcessingComplete(
TestRunAttachmentsProcessingCompleteEventArgs attachmentsProcessingCompleteEventArgs,
IEnumerable<AttachmentSet>? lastChunk)
{
_eventsHandler.HandleTestRunAttachmentsProcessingComplete(
attachmentsProcessingCompleteEventArgs,
lastChunk);
}

public void HandleTestRunAttachmentsProcessingProgress(
TestRunAttachmentsProcessingProgressEventArgs attachmentsProcessingProgressEventArgs)
{
_eventsHandler.HandleTestRunAttachmentsProcessingProgress(
attachmentsProcessingProgressEventArgs);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,16 @@ public void HandleLogMessage(TestMessageLevel level, string? message)

public void HandleRawMessage(string rawMessage)
{
_testSessionEventsHandler.HandleRawMessage(rawMessage);
// No-op by design.
//
// For out-of-process vstest.console, raw messages are passed to the translation layer but
// they are never read and don't get passed to the actual events handler in TW. If they
// were (as it happens for in-process vstest.console since there is no more translation
// layer) a NotImplemented exception would be raised as per the time this of writing this
// note.
//
// Consider changing this logic in the future if TW changes the handling logic for raw
// messages.
}

public void HandleStartTestSessionComplete(StartTestSessionCompleteEventArgs? eventArgs)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#if FIX_NULLABLE_CONFLICTS
extern alias Abstraction;
#endif

using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

#if FIX_NULLABLE_CONFLICTS
using Abstraction::Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
#else
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
#endif
using Microsoft.VisualStudio.TestPlatform.Utilities;

namespace Microsoft.VisualStudio.TestPlatform.Execution;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#if FIX_NULLABLE_CONFLICTS
extern alias Abstraction;
#endif

using System;
using System.IO;

using Microsoft.VisualStudio.TestPlatform.CoreUtilities;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;

#if FIX_NULLABLE_CONFLICTS
using Abstraction::Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
using Abstraction::Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces;
#else
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces;
#endif

using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces;

namespace Microsoft.VisualStudio.TestPlatform.Execution;
Expand Down
17 changes: 17 additions & 0 deletions src/Microsoft.TestPlatform.PlatformAbstractions/Friends.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Runtime.CompilerServices;

#region Product Assemblies

[assembly: InternalsVisibleTo("vstest.console, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("vstest.console.arm64, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]

#endregion

#region Test Assemblies

[assembly: InternalsVisibleTo("vstest.console.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]

#endregion
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,3 @@ static Microsoft.VisualStudio.TestPlatform.ObjectModel.PlatformEqtTrace.ErrorOnI
static Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.PlatformAssemblyExtensions.GetAssemblyLocation(this System.Reflection.Assembly! assembly) -> string!
Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces.IProcessHelper.GetProcessArchitecture(int processId) -> Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.PlatformArchitecture
Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.ProcessHelper.GetProcessArchitecture(int processId) -> Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.PlatformArchitecture

Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ public partial class ProcessHelper : IProcessHelper
private static readonly string Arm = "arm";
private readonly Process _currentProcess = Process.GetCurrentProcess();

#if !NET5_0_OR_GREATER
private IEnvironment _environment;
#endif

/// <summary>
/// Default constructor.
Expand All @@ -37,9 +39,20 @@ public ProcessHelper() : this(new PlatformEnvironment())

internal ProcessHelper(IEnvironment environment)
{
#if !NET5_0_OR_GREATER
_environment = environment;
#endif
}

/// <summary>
/// Gets or sets the set of environment variables to be used when spawning a new process.
/// Should this set of environment variables be null, the environment variables inherited from
/// the parent process will be used.
/// </summary>
internal static IDictionary<string, string?>? ExternalEnvironmentVariables { get; set; }

internal static bool InheritEnvironmentVariables { get; set; } = true;

/// <inheritdoc/>
public object LaunchProcess(string processPath, string? arguments, string? workingDirectory, IDictionary<string, string?>? envVariables, Action<object?, string?>? errorCallback, Action<object?>? exitCallBack, Action<object?, string?>? outputCallBack)
{
Expand Down Expand Up @@ -77,6 +90,35 @@ void InitializeAndStart()

process.EnableRaisingEvents = true;

// When vstest.console is started in its own process in VisualStudio it is TestWindowStoreHost that starts it.
// TestWindowStoreHost inherits environment variables from ServiceHost and DevEnv. Those env variables,
// contain multiple "internal" environment variables, and they also contain DOTNET_ROOT pointing to the
// .NET that is shipped with VisualStudio. So to work around this, vstest.console is given a set of environment
// variables that has only variables that DevEnv was started with. So it gets a "clean" set of env variables.
//
// When we run vstest.console in process, we cannot start ourselves with the same clean set of env variables,
// and the best we can do is to start our child processes (testhost / datacollector) with this environment.
// To do that we pass that set of "clean" env variables down to the ProcessHelper, and use those instead
// of all the variables that are set in the current process.
if (ExternalEnvironmentVariables is not null)
{
if (!InheritEnvironmentVariables)
{
process.StartInfo.EnvironmentVariables.Clear();
}

foreach (var kvp in ExternalEnvironmentVariables)
{
if (kvp.Value is null)
{
continue;
}

process.StartInfo.AddEnvironmentVariable(kvp.Key, kvp.Value);
}
}

// Set additional environment variables.
if (envVariables != null)
{
foreach (var kvp in envVariables)
Expand Down
8 changes: 6 additions & 2 deletions src/vstest.console/CommandLine/Executor.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

extern alias Abstraction;

using System;
using System.Collections.Generic;
using System.Diagnostics;
Expand All @@ -18,8 +20,10 @@
using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Tracing.Interfaces;
using Microsoft.VisualStudio.TestPlatform.Execution;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces;

using Abstraction::Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
using Abstraction::Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces;

using Microsoft.VisualStudio.TestPlatform.Utilities;

using CommandLineResources = Microsoft.VisualStudio.TestPlatform.CommandLine.Resources.Resources;
Expand Down
28 changes: 26 additions & 2 deletions src/vstest.console/HandlerToEventsRegistrarAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,19 @@ public DiscoveryHandlerToEventsRegistrarAdapter(ITestDiscoveryEventsHandler2 han
_handleDiscoveredTests += (_, e) => _handler.HandleDiscoveredTests(e.DiscoveredTestCases);
_handleLogMessage += (_, e) => _handler.HandleLogMessage(e.Level, e.Message);
_handleDiscoveryComplete += (_, e) => _handler.HandleDiscoveryComplete(e, null);
_handleRawMessage += (_, e) => _handler.HandleRawMessage(e);
_handleRawMessage += (_, e) =>
{
// No-op by design.
//
// For out-of-process vstest.console, raw messages are passed to the translation layer but
// they are never read and don't get passed to the actual events handler in TW. If they
// were (as it happens for in-process vstest.console since there is no more translation
// layer) a NotImplemented exception would be raised as per the time this of writing this
// note.
//
// Consider changing this logic in the future if TW changes the handling logic for raw
// messages.
};
}

public void LogWarning(string message)
Expand Down Expand Up @@ -60,7 +72,19 @@ public RunHandlerToEventsRegistrarAdapter(ITestRunEventsHandler handler)
{
_handler = handler;
_handleLogMessage = (_, e) => _handler.HandleLogMessage(e.Level, e.Message);
_handleRawMessage = (_, e) => _handler.HandleRawMessage(e);
_handleRawMessage = (_, e) =>
{
// No-op by design.
//
// For out-of-process vstest.console, raw messages are passed to the translation layer but
// they are never read and don't get passed to the actual events handler in TW. If they
// were (as it happens for in-process vstest.console since there is no more translation
// layer) a NotImplemented exception would be raised as per the time this of writing this
// note.
//
// Consider changing this logic in the future if TW changes the handling logic for raw
// messages.
};
_handleTestRunComplete = (_, e) => _handler.HandleTestRunComplete(e, null, null, null);
_handleTestRunStatsChange = (_, e) => _handler.HandleTestRunStatsChange(e);
}
Expand Down
28 changes: 22 additions & 6 deletions src/vstest.console/InProcessVsTestConsoleWrapper.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

extern alias Abstraction;

using System;
using System.Collections.Generic;
using System.Globalization;
Expand All @@ -16,11 +18,13 @@
using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers;
using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Tracing;
using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Tracing.Interfaces;
using Microsoft.VisualStudio.TestPlatform.Execution;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Payloads;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
using Abstraction::Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces;
using Microsoft.VisualStudio.TestPlatform.VsTestConsole.TranslationLayer.Interfaces;
Expand Down Expand Up @@ -52,7 +56,8 @@ public InProcessVsTestConsoleWrapper(ConsoleParameters consoleParameters)
requestSender: new VsTestConsoleRequestSender(),
testRequestManager: null,
executor: new Executor(ConsoleOutput.Instance),
testPlatformEventSource: TestPlatformEventSource.Instance)
testPlatformEventSource: TestPlatformEventSource.Instance,
new())
{ }

internal InProcessVsTestConsoleWrapper(
Expand All @@ -61,8 +66,13 @@ internal InProcessVsTestConsoleWrapper(
ITranslationLayerRequestSender requestSender,
ITestRequestManager? testRequestManager,
Executor executor,
ITestPlatformEventSource testPlatformEventSource)
ITestPlatformEventSource testPlatformEventSource,
UiLanguageOverride languageOverride)
{
// Setting the culture specified by user here since there's no more vstest.console process
// to set it for us. See vstest.console Main method for more info.
languageOverride.SetCultureSpecifiedByUser();

EqtTrace.Info("VsTestConsoleWrapper.StartSession: Starting VsTestConsoleWrapper session.");

_environmentVariableHelper = environmentVariableHelper;
Expand All @@ -89,9 +99,15 @@ internal InProcessVsTestConsoleWrapper(
consoleParameters.PortNumber = port;

// Start vstest.console.
// TODO: under VS we use consoleParameters.InheritEnvironmentVariables, we take that
// into account when starting a testhost, or clean up in the service host, and use the
// desired set, so all children can inherit it.
// Running vstest.console in process means we inherit all environment variables from the
// process we load the wrapper into. We do not want to alter this environment since that
// would mean we may interfer with the way the host process works. However, certain
// alterations are desired. The solution is to pass the environment variables we get via
// the console parameters directly to the testhost process and make sure that at least the
// testhost environment is predictable.
ProcessHelper.ExternalEnvironmentVariables = consoleParameters.EnvironmentVariables;
ProcessHelper.InheritEnvironmentVariables = consoleParameters.InheritEnvironmentVariables;

foreach (var pair in consoleParameters.EnvironmentVariables)
{
if (pair.Value is null)
Expand Down Expand Up @@ -869,7 +885,7 @@ public async Task ProcessTestRunAttachmentsAsync(
await Task.Run(() =>
TestRequestManager?.ProcessTestRunAttachments(
attachmentProcessingPayload,
eventsHandler,
new InProcessTestRunAttachmentsProcessingEventsHandler(eventsHandler),
new ProtocolConfig { Version = _highestSupportedVersion }),
CancellationToken.None)
.ConfigureAwait(false);
Expand Down
6 changes: 4 additions & 2 deletions src/vstest.console/Processors/AeDebuggerArgumentProcessor.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

extern alias Abstraction;

using System;
using System.Collections.Generic;
using System.Diagnostics;
Expand All @@ -13,8 +15,8 @@
using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers;
using Microsoft.VisualStudio.TestPlatform.Execution;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces;
using Abstraction::Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
using Abstraction::Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces;
Expand Down
Loading