Fixes #4804. Unit Tests are not running in degraded mode#4805
Fixes #4804. Unit Tests are not running in degraded mode#4805BDisp wants to merge 24 commits intogui-cs:v2_developfrom
Conversation
…n the ReadFile or XunitAutoGeneratedEntryPoint
|
In both VS2026 and VSCode, all unit tests pass. I think it has to do with the fact that the CI pipelines aren't running on a real console like on our machines, because the tests actually need to read the stream. I have no idea. |
|
This only happens on the windows runner, right? |
Yes, the crash only happens in the Windows runner. All the native Windows, Unix, and .NET functions (Console.IsInputRedirected || Console.IsOutputRedirected) return true if unit tests are being executed in their own environment, therefore they are never in degraded mode. If the unit tests are run on our own machines they pass, but if they are run in the CI pipeline tests they fail. I assume this is because they are not effectively connected to a terminal with a keyboard. Given this, it seems that checking if the input or output is not redirected is no longer reliable. If the Read method of each driver should not be executed in the unit tests, then another solution must be considered, although in the Unix system Read does not block, only the ReadFile in Windows. |
| /// <returns> | ||
| /// <see langword="true"/> if the test execution flag is set; otherwise, <see langword="false"/>. | ||
| /// </returns> | ||
| public static bool IsRunningInTest () => AppContext.TryGetSwitch ("Runtime.IsTestProject", out bool isTest) && isTest; |
There was a problem hiding this comment.
I'd much prefer this to be on IDriver. I worked hard to ensure there was no coupling from drivers to IApplication and this undoes that.
Can you refactor this such that it's a property on IDriver instead?
There was a problem hiding this comment.
Sure, I was just testing and I really thought it wasn't the proper way. So I'll include it in IDriver as a property and implement it in DriverImpl. Does that sound good to you?
There was a problem hiding this comment.
Thinking about it, this method isn't characteristic of IDriver because it refers to the type of application being executed. I think it's better to add it as a property in IApplication and implement it in ApplicationImpl. I think that would be the right way. What do you think?
There was a problem hiding this comment.
Sorry. Forget my previous comment. The reason it's included in IDriver is that practically all the classes that use it are also used by IDriver. So you were right in your reasoning. Thanks.
There was a problem hiding this comment.
The problem is that besides creating a property in IDriver and implementing it in DriverImpl, I'll also have to create the same property in IInput and IOutput. Don't you think that's too much work for just one property, which could even be static because when one test is running, all the others will run as well? I await your opinion and will work on the flaws in Linux and Mac.
There was a problem hiding this comment.
Because it's also used in several places. See the image below. If the IInput and IOutput interfaces had the IDriver property, then in their implementations it would be enough to call something like if (Driver.IsRunningInTest). Then you also have the case of the static class ClipboardProcessRunner, which adds even more complexity. The UnixTerminalHelper class would be easier because it's only called by AnsiOutput and UnixOutput, and you would just need to add a new parameter bool isRunningInTest to its Suspend method. The most complicated to solve would be ClipboardProcessRunner because it doesn't have any reference to IDriver, IInput, and IOutput. With this explanation, see if you can find the best solution.
There was a problem hiding this comment.
I thought this only impacts windows.
There was a problem hiding this comment.
I thought this only impacts windows.
That was my initial perception, but after the tests failed with all the drivers, I verified that all the low-level reading functions were actually being executed.
Unfortunately, I still don't understand why the tests are still failing. The API could actually be used without the need for Task.Delay, but rather by signaling an event. Now we just need to figure out where.
There was a problem hiding this comment.
Try this: set an env variable in the yml. Have the IInput impls check for that variable.
There may already be an env variable set we can use.
There was a problem hiding this comment.
Try this: set an env variable in the yml. Have the IInput impls check for that variable.
There may already be an env variable set we can use.
But the error is no longer due to low-level functions because they no longer execute with the configuration in the test projects. The problem now is that not all injected keys have yet been processed by the input processor.
|
Ok. I'll shut up until you make progress on narrowing down the problem. It does seem odd to me though that before the work in this PR only the Windows runner was failing. Now all of them are. Thanks for continuing to work on this. Let me know how/if I can help. |
|
JFYI: https://xunit.net/docs/capturing-output We should NOT use this btw. But it does point to xunit3 wrapping console output. It's possible they also wrap console input or the new arch somehow impacts it. I stand by my suggestion that we have the drivers check for an evn var at initalization and disable real read/write paths if detected (degraded mode). The best and officially recommended environment variable defined by GitHub to detect that your code (e.g., tests, build scripts, or app logic) is running inside a GitHub Actions workflow is: Value: Always set to "true" (as a string) when the workflow is executing on a GitHub Actions runner. Why it's the top choice: It's explicitly documented by GitHub for this exact purpose: to differentiate between local runs and CI runs in GitHub Actions. bool IsGitHubActions = Environment.GetEnvironmentVariable("GITHUB_ACTIONS") == "true"; |
|
I don't understand how your explanation solves this specific case. Locally, the low-level methods were being executed when they shouldn't be. By configuring the unit test files and creating the DriverImpl.IsRunningInTest property, this problem was resolved, and now the tests don't fail locally (degraded mode). What I find strange is that CI pipelines are also running in degraded mode and still failing, sometimes Windows and Mac passed, but Ubuntu always failed. I think I'll give up on this and close the PR, what do you think? |
|
I see. You are trying to solve two related but separate issues here. I am just focusing on the gh runner issue. However I think my suggestion could be useful for both: when running tests the drivers should NEVER use the real read/write path. Thus, just set an environment variable in the test .csproj that the driver Init code checks. |
I added the following configuration to all test projects, which is still more advisable than using environment variables because it's AOT compatible. <ItemGroup>
<RuntimeHostConfigurationOption
Include="Runtime.IsTestProject"
Value="true"
Trim="false" />
</ItemGroup>I also added the following property to access the project settings. Do you think that's bad? public static bool IsRunningInTest => AppContext.TryGetSwitch ("Runtime.IsTestProject", out bool isTest) && isTest; |
|
I think we learned last time we had an "IsRunningTests" flag that the name was too broad and ended up being confusing. I suggest a name that's very specific to how it's used: DisableDriverRealIO. |
Done in 4d97378. |
|
Now don't you need to revert all the other chanaes you made here that are no actually needed? |
I've changed the titles of the issue and the fix because the CI pipeline tests are still failing, and I'm giving up. If there's anything else to fix, please let me know. |
Fixes
The main reason this problem is occurring is because the unit tests are not running in degraded mode, since with xunit.v3 an executable file is created to perform the tests (.exe on Windows and without an extension on Linux and Mac).
Proposed Changes/Todos
Pull Request checklist:
CTRL-K-Dto automatically reformat your files before committing.dotnet testbefore commit///style comments)