Skip to content

Commit

Permalink
GD-124: Use LaunchProcessWithDebuggerAttached instead of `AttachDeb…
Browse files Browse the repository at this point in the history
…uggerIfNeed` for Rider 2024.2 (#130)
  • Loading branch information
MikeSchulze authored Jul 3, 2024
1 parent 8f8327b commit 22007d7
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 34 deletions.
1 change: 1 addition & 0 deletions api/src/api/TestAdapterReporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public TestAdapterReporter()

public void Dispose()
{
Console.WriteLine("TestAdapterReporter: Disconnecting from GdUnit4 test report server.");
writer?.WriteLine("TestAdapterReporter: Disconnecting from GdUnit4 test report server.");
writer?.Dispose();
client.Dispose();
Expand Down
11 changes: 10 additions & 1 deletion gdUnit4Net.sln.DotSettings.user
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/Environment/UnitTesting/CaptureOutputInternal/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=f09f2716_002D50bf_002D41af_002D9ed4_002Dca37734adfd8/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="BoolAssertTest" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=0160c73c_002D2aac_002D4853_002Db87b_002D1a0a5dfae94c/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="BoolAssertTest" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;TestAncestor&gt;&#xD;
&lt;TestId&gt;VsTest::B97C5043-B4BE-4156-BE0F-FDCBDECA61F6::net8.0::executor://gdunit4.testadapter/#GdUnit4.Tests.Asserts.BoolAssertTest&lt;/TestId&gt;&#xD;
&lt;/TestAncestor&gt;&#xD;
&lt;/SessionState&gt;</s:String>












<s:String x:Key="/Default/Housekeeping/UnitTestingMru/UnitTestRunner/LoggingInternal/@EntryValue">TRACE</s:String>
<s:String x:Key="/Default/Housekeeping/UnitTestingMru/UnitTestRunner/RunConfigurationFilename/@EntryValue">D:\development\workspace\gdUnit4Net\test\.runsettings</s:String></wpf:ResourceDictionary>
2 changes: 1 addition & 1 deletion test/project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ config_version=5
[application]

config/name="gdUnit4Test"
config/features=PackedStringArray("4.2", "4.2.1", "C#", "Forward Plus")
config/features=PackedStringArray("4.3", "C#", "Forward Plus")
config/icon="res://icon.svg"

[dotnet]
Expand Down
98 changes: 66 additions & 32 deletions testadapter/src/execution/TestExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace GdUnit4.TestAdapter.Execution;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
using Microsoft.Win32.SafeHandles;

using Settings;

Expand All @@ -34,6 +35,9 @@ public TestExecutor(RunConfiguration configuration, GdUnit4Settings gdUnit4Setti
this.gdUnit4Settings = gdUnit4Settings;
}

private object CancelLock { get; } = new();
private object ProcessLock { get; } = new();

#pragma warning disable IDE0052 // Remove unread private members
private int ParallelTestCount { get; set; }
#pragma warning restore IDE0052 // Remove unread private members
Expand All @@ -42,7 +46,7 @@ public TestExecutor(RunConfiguration configuration, GdUnit4Settings gdUnit4Setti

public void Cancel()
{
lock (this)
lock (CancelLock)
{
Console.WriteLine("Cancel triggered");
try
Expand All @@ -52,16 +56,13 @@ public void Cancel()
}
catch (Exception)
{
//frameworkHandle.SendMessage(TestMessageLevel.Error, @$"TestRunner ends with: {e.Message}");
//fh.SendMessage(TestMessageLevel.Error, @$"TestRunner ends with: {e.Message}");
}
}
}

public void Dispose()
{
pProcess?.Dispose();
GC.SuppressFinalize(this);
}
=> pProcess?.Dispose();

public void Run(IFrameworkHandle frameworkHandle, IRunContext runContext, IReadOnlyList<TestCase> testCases)
{
Expand All @@ -85,7 +86,8 @@ public void Run(IFrameworkHandle frameworkHandle, IRunContext runContext, IReadO
var debugArg = runContext.IsBeingDebugged ? "-d" : "";

using var eventServer = new TestEventReportServer();
Task.Run(() => eventServer.Start(frameworkHandle, testCases));
// ReSharper disable once AccessToDisposedClosure
var testEventServerTask = Task.Run(() => eventServer.Start(frameworkHandle, testCases));

//var filteredTestCases = filterExpression != null
// ? testCases.FindAll(t => filterExpression.MatchTestCase(t, (propertyName) =>
Expand All @@ -94,7 +96,7 @@ public void Run(IFrameworkHandle frameworkHandle, IRunContext runContext, IReadO
// return t.GetPropertyValue(testProperty);
// }) == false)
// : testCases;
var testRunnerScene = "res://gdunit4_testadapter/TestAdapterRunner.tscn"; //Path.Combine(workingDirectory, @$"{temp_test_runner_dir}/TestRunner.tscn");
var testRunnerScene = "res://gdunit4_testadapter/TestAdapterRunner.tscn";
var arguments = $"{debugArg} --path . {testRunnerScene} --testadapter --configfile=\"{configName}\" {gdUnit4Settings.Parameters}";
frameworkHandle.SendMessage(TestMessageLevel.Informational, @$"Run with args {arguments}");
var processStartInfo = new ProcessStartInfo(@$"{GodotBin}", arguments)
Expand All @@ -109,30 +111,62 @@ public void Run(IFrameworkHandle frameworkHandle, IRunContext runContext, IReadO
WorkingDirectory = @$"{workingDirectory}"
};

using (pProcess = new Process { StartInfo = processStartInfo })
{
pProcess.EnableRaisingEvents = true;
pProcess.ErrorDataReceived += StdErrorProcessor(frameworkHandle);
pProcess.Exited += ExitHandler(frameworkHandle);
pProcess.Start();
pProcess.BeginErrorReadLine();
pProcess.BeginOutputReadLine();
AttachDebuggerIfNeed(runContext, frameworkHandle, pProcess);
while (!pProcess.WaitForExit(SessionTimeOut))
Thread.Sleep(100);
try
{
pProcess.Kill(true);
frameworkHandle.SendMessage(TestMessageLevel.Informational, @$"Run TestRunner ends with {pProcess.ExitCode}");
}
catch (Exception e)
{
frameworkHandle.SendMessage(TestMessageLevel.Error, @$"Run TestRunner ends with: {e.Message}");
}
finally
lock (ProcessLock)
if (runContext.IsBeingDebugged && frameworkHandle is IFrameworkHandle2 fh2 && fh2.GetType().ToString().Contains("JetBrains") &&
fh2.GetType().Assembly.GetName().Version >= new Version("2.16.1.14"))
{
frameworkHandle.SendMessage(TestMessageLevel.Informational, $"JetBrains Rider detected {fh2.GetType().Assembly.GetName().Version}");
RunDebugRider(fh2, processStartInfo);
File.Delete(configName);
}
else
using (pProcess = new Process { StartInfo = processStartInfo })
try
{
pProcess.EnableRaisingEvents = true;
pProcess.ErrorDataReceived += StdErrorProcessor(frameworkHandle);
pProcess.Exited += ExitHandler(frameworkHandle);
pProcess.Start();
pProcess.BeginErrorReadLine();
pProcess.BeginOutputReadLine();
AttachDebuggerIfNeed(runContext, frameworkHandle, pProcess);
pProcess.WaitForExit(SessionTimeOut);
frameworkHandle.SendMessage(TestMessageLevel.Informational, @$"Run TestRunner ends with {pProcess.ExitCode}");
pProcess.Kill(true);
}
catch (Exception e)
{
frameworkHandle.SendMessage(TestMessageLevel.Error, @$"Run TestRunner ends with: {e.Message}");
}
finally { File.Delete(configName); }

// wait until all event messages are processed or the client is disconnected
testEventServerTask.Wait(TimeSpan.FromSeconds(2));
}

private void RunDebugRider(IFrameworkHandle2 fh2, ProcessStartInfo psi)
{
// EnableShutdownAfterTestRun is not working we need to use SafeHandle the get the process running until the ExitCode is getted
fh2.EnableShutdownAfterTestRun = true;
Console.WriteLine($"Debug process started {psi.FileName} {psi.WorkingDirectory} {psi.Arguments}");
var processId = fh2.LaunchProcessWithDebuggerAttached(psi.FileName, psi.WorkingDirectory, psi.Arguments, psi.Environment);
pProcess = Process.GetProcessById(processId);
SafeProcessHandle? processHandle = null;
try
{
processHandle = pProcess.SafeHandle;
var isExited = pProcess.WaitForExit(SessionTimeOut);
// it never exits on macOS ?
Console.WriteLine($"Process exited: HasExited: {pProcess.HasExited} {isExited} {processHandle}");
// enforce kill the process has also no affect on macOS
pProcess.Kill(true);
Console.WriteLine($"Process exited: HasExited: {pProcess.HasExited} {processHandle.IsClosed}");
// this line fails on macOS, maybe the SafeHandle works only on windows
//fh2.SendMessage(TestMessageLevel.Informational, @$"Run TestRunner ends with {pProcess.ExitCode}");
}
finally
{
processHandle?.Dispose();
}
}

Expand All @@ -141,7 +175,7 @@ private void InstallTestRunnerAndBuild(IFrameworkHandle frameworkHandle, string
var destinationFolderPath = Path.Combine(workingDirectory, @$"{TempTestRunnerDir}");
if (Directory.Exists(destinationFolderPath))
return;
frameworkHandle.SendMessage(TestMessageLevel.Informational, "Install GdUnit4 TestRunner");
frameworkHandle.SendMessage(TestMessageLevel.Informational, $"Installing GdUnit4 `TestRunner` at {destinationFolderPath}...");
InstallTestRunnerClasses(destinationFolderPath);
var processStartInfo = new ProcessStartInfo(@$"{GodotBin}", @"--path . --headless --build-solutions --quit-after 20")
{
Expand All @@ -162,11 +196,11 @@ private void InstallTestRunnerAndBuild(IFrameworkHandle frameworkHandle, string
try
{
process.Kill(true);
frameworkHandle.SendMessage(TestMessageLevel.Informational, $"TestRunner installed: {process.ExitCode}");
frameworkHandle.SendMessage(TestMessageLevel.Informational, $"GdUnit4 `TestRunner` successfully installed: {process.ExitCode}");
}
catch (Exception e)
{
frameworkHandle.SendMessage(TestMessageLevel.Error, @$"TestRunner ends with: {e.Message}");
frameworkHandle.SendMessage(TestMessageLevel.Error, @$"Install GdUnit4 `TestRunner` ends with: {e.Message}");
}
}

Expand Down

0 comments on commit 22007d7

Please sign in to comment.