Cancel/abort not honored when sent before custom host launch#1543
Cancel/abort not honored when sent before custom host launch#1543abhishkk merged 20 commits intomicrosoft:masterfrom
Conversation
| else | ||
| { | ||
| int processId = this.customTestHostLauncher.LaunchTestHost(testHostStartInfo); | ||
| int processId = this.customTestHostLauncher.LaunchTestHost(testHostStartInfo, cancellationToken); |
There was a problem hiding this comment.
We are breaking the API here. Is customTestHostLauncher used by others also? Interface ITesHostLauncher is in ObjectModel.
If its used by others, we need to introduce something called IsCancellable in ITestHostLauncher which will be used here to switch between overriden calls of customTestHostLauncher.LaunchTestHost.
There was a problem hiding this comment.
There was a problem hiding this comment.
I confirmed from Mayank. It will not be breaking change.
| { | ||
| using Microsoft.VisualStudio.TestPlatform.ObjectModel; | ||
| using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces; | ||
| using System.Threading; |
There was a problem hiding this comment.
Threading [](start = 17, length = 9)
nitpick: sort using..
| EqtTrace.Verbose("TestRunRequest.Abort: Aborting."); | ||
|
|
||
| lock (this.syncObject) | ||
| lock (this.abortSyncObject) |
There was a problem hiding this comment.
abortSyncObject [](start = 23, length = 15)
isn't the usage of the sync object to synchronize the access to the executionmanager ?
There was a problem hiding this comment.
All execution related requests, like ExecuteAsync, HandleTestRunComplete, HandleTestRunStatsChange, HandleLogMessage are under same sync object.
But we want to respect cancel, abort and don't want to wait if some of the above request are going on. Thus separate lock objects for them
There was a problem hiding this comment.
Potentially reuse the same object for cancel and abort then?
| // Cycle through the messages that the datacollector sends. | ||
| // Currently each of the operations are not separate tasks since they should not each take much time. This is just a notification. | ||
| while (!isDataCollectionComplete) | ||
| while (!isDataCollectionComplete && !isCancelled) |
There was a problem hiding this comment.
isCancelled [](start = 49, length = 11)
won't we fail to receive data (testruncomplete )
There was a problem hiding this comment.
In case of cancellation and abort, we dont get any attachments from data collectors and simply cancels the run. So adding isCancelled will do the same thing. For non-cancelled run, we will be able to successfully able to receive data
| @@ -260,13 +270,19 @@ public void InitializeExecution(IEnumerable<string> pathToAdditionalExtensions) | |||
|
|
|||
| /// <inheritdoc /> | |||
| public void StartTestRun(TestRunCriteriaWithSources runCriteria, ITestRunEventsHandler eventHandler) | |||
There was a problem hiding this comment.
StartTestRun [](start = 20, length = 12)
why do we need two signatures..? TP is an internal interface..?
| /// <param name="runCriteria">RunCriteria for test run</param> | ||
| /// <param name="eventHandler">EventHandler for test run events</param> | ||
| /// <param name="cancellationToken">Cancellation token</param> | ||
| void StartTestRun(TestRunCriteriaWithTests runCriteria, ITestRunEventsHandler eventHandler, CancellationToken cancellationToken); |
There was a problem hiding this comment.
StartTestRun [](start = 13, length = 12)
same question.. is this a public interface ?
There was a problem hiding this comment.
Done. Modified existing methods.
| else | ||
| { | ||
| int processId = this.customTestHostLauncher.LaunchTestHost(testHostStartInfo); | ||
| int processId = this.customTestHostLauncher.LaunchTestHost(testHostStartInfo, cancellationToken); |
There was a problem hiding this comment.
Add this is dotnet runtime
| }; | ||
|
|
||
| // Registering cancellationToken to set waitHandle (whenever request is cancelled). | ||
| var cancellationTokenRegistration = cancellationToken.Register(() => waitHandle.Set()); |
| // Set a default message and wait for test host to exit for a moment | ||
| reason = CommonResources.UnableToCommunicateToTestHost; | ||
| if (this.clientExited.Wait(this.clientExitedWaitTime)) | ||
| if (this.clientExited.Wait(this.clientExitedWaitTime) && !cancellationToken.IsCancellationRequested) |
There was a problem hiding this comment.
hmm, should this be the first condition then?
There was a problem hiding this comment.
No. If cancellation flag is checked first and it returns false, and then while waiting cancellation occurs, then waitHandle will be set because of cancellation and thus enter in if condition (which is wrong as wait is set by cancel)
There was a problem hiding this comment.
I was thinking the other way round where we actually end up waiting for a while, figure out its cancelled and head to the else part which seems like a wasted wait...
There was a problem hiding this comment.
We are already doing that in this PR. Earlier I did a CancellationToken.Register(() => this.clientExited) which I latter changed to this.clientExited.Wait(this.clientExitedWaitTime, CancellationToken) on your recommendation. In either case, clientExited will return immediately if cancellation happened. Let me know if i am understanding it incorrectly.
|
|
||
| private bool LaunchTestHostAsync(TestProcessStartInfo testHostStartInfo, CancellationToken token) | ||
| { | ||
| this.CancellationTokenSource.Token.ThrowIfCancellationRequested(); |
There was a problem hiding this comment.
should this be called out in the protocol doc? Looks like a cancel is going to be an abrupt stop to a request no matter where in the sequence we are currently.
There was a problem hiding this comment.
We are cancelling abruptly only before the test execution is actually started and then sending HandleTestRunComplete.
Once test execution is started by test host, we send cancel request to test host and which passes the cancel request to adapters.
@cltshivash @singhsarab Should this be documented?
There was a problem hiding this comment.
yup, got that but most clients would not expect a TestRunComplete when negotiating protocol unless told otherwise.... Was a separate message for cancellation considered for scenarios like these? Might be a bigger change but worth a fluid protocol.
There was a problem hiding this comment.
TestRequestManager today waits for completion in all scenarios. I will check if this is already documented and if not, will discuss with the team and document it.
| /// <param name="defaultTestHostStartInfo">Default TestHost Process Info</param> | ||
| /// <param name="cancellationToken">The cancellation Token.</param> | ||
| /// <returns>Process id of the launched test host</returns> | ||
| int LaunchTestHost(TestProcessStartInfo defaultTestHostStartInfo, CancellationToken cancellationToken); |
There was a problem hiding this comment.
Will require a corresponding change in TPV1 OM. TE implements this for debugging which would need a change as well.
There was a problem hiding this comment.
This interface is used by run time provider only for launching the custom host via custom host launcher.
Why changes are required in TPV1 OM?
Even though if TE uses it as an interface for their internal purpose, there will no breaking change here (as TPv1 OM is used both while build and run time. TPV2 OM is not loaded.) Please correct me if i am missing something here.
There was a problem hiding this comment.
Fare, but shouldn't we be consistent? Bare in mind that the Console wrapper and interfaces assemblies are loaded in VS and this could result in inadvertent runtime failures.
There was a problem hiding this comment.
@cltshivash @singhsarab @AbhitejJohn
Am I missing something here? AFIAK ITestHostLauncher is meant only for runtime provider and it is loaded in vstest console only. Neither translation layer, nor test host or any other process from TP side uses this except vstest.console.
If TE is using this interface for their internal purpose, then it is using TPV1 OM and loading TPV1 OM. So how the behavior is inconsistent? I don't feel comfortable changing TPV1 OM unless it's a breaking change.
|
Do validate that UWP does work with these changes |
…into cancelNotHonored
Issue:
#1540
Changes done:
@AbhitejJohn Please verify IDE side changes considering above changes. I have done validations from my end. Let me know if there are any issues.
@mayankbansal018 Regarding # 7, do we need make any changes in UWP runtime provider to respect cancellation?