vstest: 'dotnet test' sometimes causes terminal to stop echoing after completion (ubuntu)
From @beevik on Saturday, December 21, 2019 7:20:52 PM
When running dotnet test on ubuntu, the terminal often stops echoing input after the command completes. It’s not 100%. Sometimes echoing remains on. I’m using the xunit testing framework.
Here are the results of typing stty -a after the terminal stops echoing:
speed 38400 baud; rows 40; columns 132; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S;
susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -ixon -ixoff -iuclc -ixany -imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig -icanon -iexten -echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc
As you can see, echo is off (-echo).
This does not appear to be a bug in xunit, as someone has reported a similar issue when using expecto instead.
Ubuntu 18.04.3 .NET Core 3.1 xunit 2.4.1
Copied from original issue: dotnet/sdk#4090
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 37
- Comments: 84 (30 by maintainers)
From @rmunn on Monday, December 23, 2019 8:18:21 PM
I’m the one who reported that issue with Expecto. I also have a vague memory of seeing this pop up with other
dotnet foocommands such asdotnet build, but I don’t have a solid example since I’m away from my desk for the holidays. Once I get a solid example I’ll mention it here.BTW, for anyone else who experiences this, you can restore your terminal to normal functionality after this issue triggers by typing
stty echofollowed by Enter.I just ran into this. Definitely annoying! After reading through this and related issues, I tried to determine minimal reproducible steps.
Environment
Findings
dotnet testfrom within a single test application’s directory.dotnet testfrom a directory with a solution file and multiple projects (mix of test and non-test projects, all added to the .sln file).dotnet test | sed -n 'l'), I’m not seeing any immediately incriminating control characters.Reproduction
From the command line, I narrowed everything down to being able to run the following commands to reproduce the issue fairly reliably:
Run
dotnet testuntil the terminal stops behaving as expected. It usually only takes me two or three attempts before the terminal “breaks.”Will try to dig in further, but I hope this helps, in the meantime.
This should be fixed by https://github.com/dotnet/msbuild/pull/6053, which will be in MSBuild v16.10.
Temporary work-around in
bashsyntax:BEFORE=$(stty -g); dotnet test --logger:"console;verbosity=detailed"; stty "${BEFORE}"or in
.bashrc:But I will just try to notify persons who commited changes related to
termios.hin .NET Runtime to maybe clarify things.@stephentoub @tmds could you take a look on this issue? In a case of
tl;drI believe the most accurate are investigations since https://github.com/microsoft/vstest/issues/2282#issuecomment-609494059When invoking
dotnet test, this leads to MsBuild processes being started:No one waits for this process to terminate. When such a process terminates after
dotnet testit restores terminal settings to what it observed at start, which may be echo off.I think the resolution is to either wait for these processes to terminate, or to not give them access to terminal by redirecting their streams.
Looking through the pal_console.c code, I noticed some interesting code interactions:
forChildparameter is false. (IfforChildis true, the ECHO flag is untouched)..,.., and...states).atexit()handler to restore those terminal settings when the process exits.So what I think might be happening could be something like this interaction between all that code:
dotnet testprocess starts up, and saves the current state of the terminal (including whether theechoflag is on or off).dotnet teststarts upecho=falsein the terminal settingsecho=falsein the terminal settings that it stores in its global variableecho=false, so any subsequent child processes that start after that point will pick upecho=falseas the settings they should restoreecho=false, then it restores those terminal settings right beforedotnet testexits, and so the user is left with a terminal that doesn’t echo.A complicated race condition, but all it requires is that some child processes complete before three seconds are up, which is not hard to have happen.
@BDisp
Can you create an issue for the font size change? As I mentioned in https://github.com/microsoft/vstest/issues/2282#issuecomment-933489651, it is not related to the echoing.
@andreujuanc
You anyhow need to port your app in the coming year to .NET 6+ to remain on a supported version.
LTS means you get security fixes. Microsoft rarely backports other fixes to minimize the chance of regressions.
@Jodacola - Running the Microsoft ® Test Execution Command Line Tool Version 16.5.0 under Ubuntu (NOT the Ubuntu WSL environment), I was able to reproduce this issue again, by cloning https://github.com/commandlineparser/commandline/ and running
dotnet testa few times. The third run triggered the issue: my typed input stopped being echoed to the terminal until I ranstty echoto turn the echo flag back on.Again, that was with version 16.5.0 of the text execution tool, running under .NET Core SDK 3.1.201.
@BDisp This focuses on the terminal echo issue. If you can reproduce the font size issue using .NET 6, create a new ticket for it.
@Forgind I think we can close this and consider it fixed .NET6+.
The solution on vstest side is what I put in https://github.com/microsoft/vstest/issues/2282#issuecomment-614620392:
This change for .NET 6: https://github.com/dotnet/runtime/pull/42303 should also make it less likely terminal ends up non-echoing after running
dotnet test.dotnet test /m:1does not exhibit the same problem asdotnet testfor meany updates on this? It’s just a huge pain to have a broken console everytime I run my test suite. I now instinctively write
stty echoaftermake test. This is affecting multiple developers in my org.I did not, I am not that familiar with fixing issues on linux terminal 🙂 Thanks for the suggestion.
@rmunn wow! 👏👏👏
That seems very plausible and very close to what we’ve been observing. To aid you with your investitgation, what happens process-wise in the repro above is that:
dotnet testkicks off build for the two test projects.build builds the projects in parallel and then starts two vstest.console processes in parallel
( each vstest.console starts a test host, testhost only writes back through socket, but not to console, so forget about it )
in each vstest.console a timer starts that will write progress indicator to console after 1s
in each console we start getting back output from testhost and writing it to screen.
at this point we have 4 threads in 2 processes that are trying to write to the console
we lock on most of the output, and Console imho does as well, so we can only do 1 console action per process at 1 time.
I totally believe that what you described is at least part of the answer, but can you share your opinion on these?
v. could be caused by clearing the progress indicator from the screen after writing test results rather than 3rd dot? I am asking because the test summary almost always stopped the execution in the same way. There are different processes running, so I don’t believe the timing was the same. I did no see anything special about the summary. I am guessing that there is a call to Clear on the ProgressIndicator when we are done running, that makes this easily reproducible? I saw it happen more consistently with xunit because it writes into console way more than mstest, and in smaller chunks.
in the repro I did not see it trigger when colors were disabled. In the repro where both sides fail it locks up silently, but with the long running test passing (in my repro the assertion is already commented out, so it behaves this way by default), outputs the same characters everytime. Can you explain that, and what the collision is?
@andreujuanc, @tmds fixed this with https://github.com/dotnet/msbuild/pull/6053. That came out in 16.10 if I remember correctly, so you would have to update .NET.
I agree, but I don’t have permission to close it. @nohwnd?
Really, using dotnet 5 the problem does not occur to me anymore 😃
@rainersigwald when I run the steps from https://github.com/microsoft/vstest/issues/2282#issuecomment-605665646:
These
dotnetprocesses are started:I see the processes
dotnet /usr/lib64/dotnet/sdk/5.0.100/MSBuild.dll /usr/lib64/dotnet/sdk/5.0.100/MSBuild.dll /nologo /nodemode:1 /nodeReuse:false /low:falseare not waited for by their parent:dotnet exec /usr/lib64/dotnet/sdk/5.0.100/MSBuild.dll -maxcpucount -verbosity:m -restore -target:VSTest -nodereuse:false -nologo.Do you know what creates these processes? I think making the parent
Process.WaitForExitits children is the proper fix for this issue.This had me stumped for a while too @WellspringCS . As @chrisheil suggests its an option that’s passed through to MSBuild to specify the maximum number of concurrent processes used. It’s documented under ‘maxCpuCount’ here https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-command-line-reference?view=vs-2019
@WellspringCS based on ths link, i think it might be an MSBuild param to run tests sequentially instead of in parallel
https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/Examples/MSBuild/MergeWith/HowTo.md
@nohwnd I think we should go with minimal changes to current behaviour and running for individual project and running same project from solution should be almost identical. The issue is that for example coverlet is executing additional steps before tests run and after tests run (for individual project). I think more about approach that all individual project runs will report tests status and attachements to some orchestrator (through port similar like in VS).
@tmds thanks for analyzing this.
@jakubch1 do you plan to solve the CC merge issue by using the msbuild to only build and figure out source paths, and then run multiple test hosts from single vsconsole? I think it would be the best way to go because that would help us here with the echoing, as well as with the parallel output, and with other issue where you can’t run multiple different TFMs from single console.
To behave similar to Windows, .NET Core disables echoing when
Consoleis used for input in some way on Linux. When a .NET Core app exits, it will restore the echoing state it captured at start.Does
dotnet testwait for all it’s children to terminate (especially the children which are given access to terminal by not redirecting streams)?I’ll try to reproduce this week using instructions from https://github.com/microsoft/vstest/issues/2282#issuecomment-605665646.
What is going on with that Travis CI log? I’m having a hard time telling where the
VSTEST_RUNNER_PROGRESS=1 VSTEST_RUNNER_COLOR=1 dotnet testrun starts and the other run ends, because it looks a bit interleaved. Does the same failure happen if you only run theVSTEST_RUNNER_PROGRESS=1 VSTEST_RUNNER_COLOR=1 dotnet testversion, and not the other two?AFAICT, colors should have no effect on this bug, so I have no idea why the VSTEST_RUNNER_PROGRESS=1 VSTEST_RUNNER_COLOR=0 run succeeds (doesn’t trigger the hang) but the VSTEST_RUNNER_PROGRESS=1 VSTEST_RUNNER_COLOR=1 run hangs. Where is the code that you wrote that handles the VSTEST_RUNNER_COLOR environment variable? I looked all over the branches of your ProgressToy repo and couldn’t find it, so I can’t tell whether you’re accidentally changing something besides color when VSTEST_RUNNER_COLOR is equal to 1.
And my availability is likely to be almost zero in the next few weeks, but I might occasionally have a spare hour to throw at this.
Pushed original repro to the travis build and it got stuck. Will try to replace the progress with another that does not move the cursor, hopefully that will fix it. Then we can talk about how it looks.