.NET/.NetCore - Profiler's SocketException when running tests via VSTest.Console
Problem
In certain cases, we can see an exception at the end of the test execution that may cause coverage loss for the last chunk of metadata cached by the agent and that may not be sent before the exception occurs
17:03:55.632 ERROR [Endpoint for 0xfa79db0f00002724] Got exception on receive: An existing connection was forcibly closed by the remote host.
17:03:55.633 DEBUG [Endpoint for 0xfa79db0f00002724] System.Net.Sockets.SocketException (10054): An existing connection was forcibly closed by the remote host.
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource<System.Int32>.GetResult(Int16 token)
at System.Threading.Tasks.ValueTask`1.ValueTaskSourceAsTask.<>c.<.cctor>b__4_0(Object state)
--- End of stack trace from previous location ---
at System.Threading.Tasks.TaskToApm.End[TResult](IAsyncResult asyncResult)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location ---
at SL.DotNet.IpcLibraryCrossPlatform.IpcTcpSocket.ReceiveInternalAsync(Int32 size, Action resetTimeoutTimer)
at SL.DotNet.IpcLibraryCrossPlatform.IpcTcpSocket.ReceiveAsync(Int32 size, Int32 timeoutMs)
at SL.DotNet.IpcLibraryCrossPlatform.IpcTcpEndpoint.ProcessConnectionRequests()
17:03:55.636 INFO [CoverageCollector / Active session 72ead1dd-d713-4f7c-86ad-87d6ad89f8ec / Profiler ID 0xFA79DB0F00002724] Profiler 'ended' event received
17:03:55.652 INFO [CoverageCollector / Active session 72ead1dd-d713-4f7c-86ad-87d6ad89f8ec] Profiler ID 0xFA79DB0F00002724 closed. Reason=Unexpected
This Exception usually happens when running your tests with an old version of the command-line tool VSTest.Console.exe wrapped with the Sealights .Net Agent run
command.
$vstest = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe"
$testsToRun = Get-Item -Path "${BuildRoot}\AcmeCoreService\UnitTests\UnitTestsCompiled\*Test*.dll" | ForEach-Object { $_.FullName } | Where-Object { $_ -notlike '*Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll' }
. sl/sldotnet/sl.dotnet.exe run --buildSessionIdFile sl/sldotnet/buildsessionid.txt --testStage "$SealightsStageName" `
--target $vstest --targetArgs "$testsToRun /Diag:`"${buildroot}\out\logs\sealights\utests\vstest_log_sl.txt`" /platform:x64 /resultsdirectory:`"${buildroot}\out\testresults1`" /logger:trx"
Cause
The test host process that executes tests is terminated by the test console immediately after the last test.
The error we see in the logs of the test console could happen even without sealights profilers attached, but because our agent wraps the test host process, it makes it a bit slower than usual and the exception is more likely to happen.
Solution
Microsoft’s VSTest.Console starting from version 17.2 (see PR #3466) supports the environment variable VSTEST_TESTHOST_SHUTDOWN_TIMEOUT
that allows to override shutdown timeout to increase it and avoid abrupt disconnection
$Env:VSTEST_TESTHOST_SHUTDOWN_TIMEOUT = 2000
An additional enhancement would be to decrease the interval for sending data from the Sealights profiler to the Sealights collector via the environment variable $Env:SL_Profiler_CoverageSamplingTimeoutSec
(Default is 5, Recommended is 2).