microsoft / vscode-dotnettools

This is a feedback repository to capture issues logged for the C# Dev Kit and related extensions from Visual Studio Code
Other
232 stars 13 forks source link

[BUG] Unable to create test controller for c# extension on macOS with Unity #384

Closed montoulieu closed 1 year ago

montoulieu commented 1 year ago

Describe the Issue

Hey there, I believe I have a unique issue happening separately from the other Unity/Mac related issues that have been cropping up from the past week.

I was able to get the latest VS Code extensions working with my Unity projects on my M1 Max MacBook and Windows 11 desktop, but for some reason can not get this project to load on my M2 Ultra Studio.

The main differences I'm seeing is in the C# Dev Kit output logs, where I can see two extra [object Object] logging in C# Dev Kit and Text Explorer errors out with a message about it not able to find a .dll file.

Can anyone help understand whats going on here? This was working perfectly before this week.

C

Dotnet path: /Users/montoulieu/Library/Application Support/Code/User/globalStorage/ms-dotnettools.vscode-dotnet-runtime/.dotnet/7.0.10/dotnet
Activating C# + C# Dev Kit + C# IntelliCode...
[Info  - 11:28:56 PM] [Program]Language server initialized

C# Dev Kit

Starting Spawn .NET server...
Starting Open a solution...
Starting Open a solution with environment service...
Starting Clear environment...
.NET server started and IPC established in 704ms
Completed Spawn .NET server (706ms)
Completed Clear environment (878ms)
Completed Open a solution with environment service (950ms)
Starting Restore solution...
Completed Open a solution (962ms)
[object Object]
[object Object]
Completed Restore solution (924ms)

C# Dev Kit - Test Explorer

Created Test Controller
Using vstest from dotnet sdk in [/usr/local/share/dotnet/sdk/7.0.400].
unable to create test controller for c# extension: Error: An error occurred when opening the file /usr/local/bin/dotnet with arguments "/usr/local/share/dotnet/sdk/7.0.400/vstest.console.dll" /parentprocessid:66317 /port:64616.
System.Exception: An error occurred when opening the file /usr/local/bin/dotnet with arguments "/usr/local/share/dotnet/sdk/7.0.400/vstest.console.dll" /parentprocessid:66317 /port:64616.
 ---> System.ComponentModel.Win32Exception (2): An error occurred trying to start process '/usr/local/bin/dotnet' with working directory '/Users/montoulieu/Code/Unity/Sports'. No such file or directory
   at System.Diagnostics.Process.ForkAndExecProcess(ProcessStartInfo startInfo, String resolvedFilename, String[] argv, String[] envp, String cwd, Boolean setCredentials, UInt32 userId, UInt32 groupId, UInt32[] groups, Int32& stdinFd, Int32& stdoutFd, Int32& stderrFd, Boolean usesTerminal, Boolean throwOnNoExec)
   at System.Diagnostics.Process.StartCore(ProcessStartInfo startInfo)
   at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
   at Microsoft.TestPlatform.VsTestConsole.TranslationLayer.VsTestConsoleProcessManager.StartProcess(ConsoleParameters consoleParameters)
   --- End of inner exception stack trace ---
   at Microsoft.TestPlatform.VsTestConsole.TranslationLayer.VsTestConsoleProcessManager.StartProcess(ConsoleParameters consoleParameters)
   at Microsoft.VisualStudio.TestWindow.Host.TestPlatformProviders.LocalTestPlatformProvider.ActivateSessionAsync(ITestWindowCallbackService testWindowCallbackService, ITestAgentBridgeCallback TestAgentBridgeCallback, Boolean enableDiagnosticLogging, RuntimeEnvironment runtimeEnvironment, IDictionary`2 environment, IDictionary`2 props, InitializeCapabilitiesRequest clientCapabilities, CancellationToken cancellationToken)
   at Microsoft.VisualStudio.TestWindow.Host.TestPlatformAgentPool.<>c__DisplayClass24_0.<<CreateRemoteAgentAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.VisualStudio.TestWindow.Utilities.EventPumpExtensions.<>c__DisplayClass4_0`1.<<EnqueueAsync>b__1>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.VisualStudio.TestWindow.Extensibility.TaskCompletionSourceExtensions.RunTaskWithCatchAsync[T](TaskCompletionSource`1 taskCompletionSource, Func`1 task)
   at Microsoft.VisualStudio.TestWindow.Logging.ILoggerExtensions.CallWithCatchAsync(IInternalLogger log, Func`1 func)
   at Microsoft.VisualStudio.TestWindow.Host.TestPlatformProvider.GetProviderAsync(ITestWindowCallbackService callbackClient, IInternalLogger logger, ITestWindowHostTelemetry telemetryService, ICollection`1 runtimeEnvironments, IDictionary`2 environmentVariables, Boolean enableDiagnosticLogging, Boolean autoInstallRuntimePrereqs, InitializeCapabilitiesRequest clientCapabilities, ITestPlatformProviderMap testPlatformProviderMap)
   at Microsoft.VisualStudio.TestWindow.Host.TestWindowStoreService.InitializeVSCodeServiceAsync(InitializeOptions initializeRequest, CancellationToken cancellationToken)
   at Microsoft.VisualStudio.TestWindow.VSCode.Service.TestWindowVSCodeService.InitializeAsync(InitializeOptions options, CancellationToken cancellationToken)

Steps To Reproduce

Try setting up a project on a M2 device with the latest dotnet, VS Code extensions and Unity extensions

Expected Behavior

A loading project

Environment Information

.NET SDK: Version: 7.0.400 Commit: 73bf45718d

Runtime Environment: OS Name: Mac OS X OS Version: 13.5 OS Platform: Darwin RID: osx.13-arm64 Base Path: /usr/local/share/dotnet/sdk/7.0.400/

Host: Version: 7.0.10 Architecture: arm64 Commit: a6dbb800a4

.NET SDKs installed: 7.0.306 [/usr/local/share/dotnet/sdk] 7.0.400 [/usr/local/share/dotnet/sdk]

.NET runtimes installed: Microsoft.AspNetCore.App 7.0.9 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 7.0.10 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.NETCore.App 7.0.9 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App] Microsoft.NETCore.App 7.0.10 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]

Other architectures found: None

Environment variables: Not set

global.json file: Not found

Learn more: https://aka.ms/dotnet/info

Download .NET: https://aka.ms/dotnet/download

peterwald commented 1 year ago

It looks like the root cause of the error is this from the log... An error occurred trying to start process '/usr/local/bin/dotnet' with working directory '/Users/montoulieu/Code/Unity/Sports'. No such file or directory

Can you confirm whether /Users/montoulieu/Code/Unity/Sports exists when this error is received?

montoulieu commented 1 year ago

Interesting. Yep I can confirm that directory is there and that is the project I'm opening.

peterwald commented 1 year ago

Is this a multi-root workspace by chance?

montoulieu commented 1 year ago

Nope, not that I know of. It's a standard Unity project initialized through Unity Hub. Let me know if theres any extra files or details I can provide to help debug.

peterwald commented 1 year ago

If you have a small repro that is ok to share, that would be very helpful.

peterwald commented 1 year ago

If you have a small repro that is ok to share, that would be very helpful.

Or maybe steps that I could use to reproduce it myself with Unity.

tom-hodgson commented 1 year ago

I get this exact same problem with my similar environment information, if I do dotnet new classlib -n Some.Project and open the project I get the error.

The working directory exists, the problem is that the process /usr/local/bin/dotnet doesn't. Looking at the original posters .NET runtimes installed it appears its the same for them too.

our dotnet runtimes are under /usr/local/share/dotnet/dotnet but for some reason the app expects it to be /usr/local/bin/dotnet

tom-hodgson commented 1 year ago

I had a dodgy symlink that I had created when i installed dotnet (some time ago):

% ls -la /usr/local/bin 

 dotnet -> missing_file

overwriting this link to the right place

sudo ln -sf /usr/local/share/dotnet/dotnet /usr/local/bin/

fixed the problem for me.

peterwald commented 1 year ago

The current implementation searches the PATH to find the instance of dotnet to invoke. If there is a file named dotnet in your path that is not a valid entrypoint to the .NET runtime, then you will experience this failure. The broken symlink noted by @tom-hodgson makes sense as a likely cause.

@montoulieu check and see if /usr/local/bin/dotnet is a valid symlink to the runtime.

Closing for now as this seems to be an installation/configuration issue.

devtram commented 1 year ago

I had a dodgy symlink that I had created when i installed dotnet (some time ago):

% ls -la /usr/local/bin 

 dotnet -> missing_file

overwriting this link to the right place

sudo ln -sf /usr/local/share/dotnet/dotnet /usr/local/bin/

fixed the problem for me.

I had same problem and I can confirm this worked out in my case...

skannoju-navico commented 11 months ago

I had a dodgy symlink that I had created when i installed dotnet (some time ago):

% ls -la /usr/local/bin 

 dotnet -> missing_file

overwriting this link to the right place

sudo ln -sf /usr/local/share/dotnet/dotnet /usr/local/bin/

fixed the problem for me.

I had same problem and I can confirm this worked out in my case...

Same. SymLink fixing worked for me.

Number0ne commented 11 months ago

I had a dodgy symlink that I had created when i installed dotnet (some time ago):

% ls -la /usr/local/bin 

 dotnet -> missing_file

overwriting this link to the right place

sudo ln -sf /usr/local/share/dotnet/dotnet /usr/local/bin/

fixed the problem for me.

This also solved my problem. đŸ’¯

steveaharan commented 4 months ago

I had a dodgy symlink that I had created when i installed dotnet (some time ago):

% ls -la /usr/local/bin 

 dotnet -> missing_file

overwriting this link to the right place

sudo ln -sf /usr/local/share/dotnet/dotnet /usr/local/bin/

fixed the problem for me.

I have this issue every couple of years when I install a new version of .net, and it takes me hours of googling until I find and remember the solution! Thank you! I'll write it on a postit note for next time ;-)

Jaculabilis commented 3 months ago

The current implementation searches the PATH to find the instance of dotnet to invoke. If there is a file named dotnet in your path that is not a valid entrypoint to the .NET runtime, then you will experience this failure.

I'm still hitting this issue even with dotnet on PATH.

I'm on NixOS 24.05, VS Code v1.89.1, ms-dotnettools.csdevkit v1.9.55, ms-dotnettools.csharp v2.39.29, dotnet 8.0.300.

dotnet is not installed locally, but I have a project-specific shell that adds dotnet to PATH:

$ which dotnet
which: no dotnet in (/run/wrappers/bin:/home/tvb/.nix-profile/bin:/nix/profile/bin:/home/tvb/.local/state/nix/profile/bin:/etc/profiles/per-user/tvb/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin)
$ nix develop --impure
$$ which dotnet
/nix/store/8y83na7h81fw5kr1msmjc7rvx329djp0-dotnet-sdk-8.0.300/bin/dotnet
$$ dotnet

Usage: dotnet [options]
Usage: dotnet [path-to-application]

Options:
  -h|--help         Display help.
  --info            Display .NET information.
  --list-sdks       Display the installed SDKs.
  --list-runtimes   Display the installed runtimes.

path-to-application:
  The path to an application .dll file to execute.

From this shell, I then launch code via code . so that VS Code inherits the dev environment. I can verify that VS Code has dotnet on PATH by checking the output for "C#":

Using dotnet configured on PATH
Dotnet path: /nix/store/8y83na7h81fw5kr1msmjc7rvx329djp0-dotnet-sdk-8.0.300/dotnet
Activating C# + C# Dev Kit...
waiting for named pipe information from server...
[stdout] {"pipeName":"/tmp/nix-shell.AgKYxk/0cde63b9.sock"}
received named pipe information from server
attempting to connect client to server...
client has connected to server
[Info  - 7:45:32 PM] [Program] Language server initialized

And "C# Dev Kit":

Starting Spawn .NET server...
Starting Open a solution...
Starting handling solution file "/path/to/project/project.sln" in Dev Kit server...
Starting Clear environment...
Using preinstalled .NET runtime at "/nix/store/8y83na7h81fw5kr1msmjc7rvx329djp0-dotnet-sdk-8.0.300/dotnet"
.NET server started and IPC established in 1390ms

However, "C# Dev Kit - Test Explorer" only outputs this:

Created Test Controller
unable to create test controller for c# extension: Error: An error occurred trying to start process 'dotnet' with working directory '/path/to/project'. No such file or directory

I'm not sure why it's just going for dotnet instead of /usr/local/bin/dotnet, as other people replying have. Given the dev shell, that's the right behavior, so that's not the problem. The problem is that it doesn't seem to be able to find it when the other extensions can. Perhaps the test explorer is setting its own PATH and losing the SDK path added by the dev shell, or looking for more than just a path to a binary, like a certain folder structure?

Another data point: if I create a symlink dotnet in the project folder...

$$ ln -s $(which dotnet)
$$ ls -l dotnet
dotnet -> /nix/store/8y83na7h81fw5kr1msmjc7rvx329djp0-dotnet-sdk-8.0.300/bin/dotnet

...the Test Explorer gets further before failing. That ./dotnet symlink seems to be enough for it to find /nix/store/.../bin/dotnet and from there the /nix/store/.../sdk/8.0.300 directory next to it, which contains testhost.dll, vstest.console.dll, MSBuild.dll, etc. I am not sure why that helps, since the project directory isn't on PATH. Yet after using the dotnet path to find the SDK, it then errors out because it can't find dotnet again!

Created Test Controller
Using vstest from dotnet sdk in [/nix/store/8y83na7h81fw5kr1msmjc7rvx329djp0-dotnet-sdk-8.0.300/sdk/8.0.300].
Initialized Test Explorer Server [2249471]
Test Store Folder: ~/.config/Code/User/workspaceStorage/792b4ef444992ea6b5892458d10c3129/ms-dotnettools.csdevkit
Test data store opened in 0.016 sec.
Initialized project system provider.
1 projects added, 0 changed, 0 removed.
Scheduling discovery: /path/to/project/Tests/bin/Debug/net8.0/Tests.dll [1723602445085]
========== Starting test discovery ==========
System.IO.FileNotFoundException: Could not find 'dotnet' host. Make sure that 'dotnet' is installed on the machine and is available in PATH environment variable.
   at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Helpers.DotnetHostHelper.GetDotnetPath() in /_/src/Microsoft.TestPlatform.CoreUtilities/Helpers/DotnetHostHelper.cs:line 80
   at Microsoft.TestPlatform.VsTestConsole.TranslationLayer.VsTestConsoleProcessManager.StartProcess(ConsoleParameters consoleParameters) in /_/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleProcessManager.cs:line 104
   at Microsoft.VisualStudio.TestWindow.Messaging.RemoteAgent.TestRunController.VsTestRunController.Create(String testConsolePath, InitializeCapabilitiesRequest clientCapabilities, IDictionary`2 environment, Boolean inheritEnvironmentVariables, ITestRunDataSink dataSink, IInternalLogger logger)
   at Microsoft.VisualStudio.TestWindow.Messaging.RemoteAgent.TestRunController.CreateVsTestRunController(ITestRunDataSink dataSink)
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at Microsoft.VisualStudio.TestWindow.Messaging.RemoteAgent.BaseTestAgentBridge.DiscoverTestsAsync(IEnumerable`1 sources, String launcherType, String launcherConfiguration, String discoverySettings, RemoteTestPlatformOptions options, CancellationToken cancellationToken)
   at Microsoft.VisualStudio.TestWindow.Host.TestPlatformProvider.DiscoverTestsAsync(DiscoverTestsRequest request, VsTestRunSession runSession, ImmutableDictionary`2 discoverSettingsMap, ImmutableArray`1 containersToDiscover, IEnumerable`1 activeEnvironments, CancellationToken cancellationToken)
========== Test discovery aborted: 0 Tests found in 64.3 ms ==========
0 tests discovered from  in 64.2605 ms

The stack trace points to DotnetHostHelper.cs, which is doing a simple TryGetExecutablePath("dotnet", out var dotnetPath). The relevant lines of that function are:

        var pathString = Environment.GetEnvironmentVariable("PATH")!;
        foreach (string path in pathString.Split(Path.PathSeparator))
        {
            string exeFullPath = Path.Combine(path.Trim(), executableBaseName);
            if (_fileHelper.Exists(exeFullPath))

So something funky is going on with how the test explorer is launched, since dotnet is findable by several other processes with the PATH from the dev shell.