Skip to content
This repository has been archived by the owner on Jul 15, 2023. It is now read-only.

Add "Cancel Running Test" status bar item #1218

Merged
merged 8 commits into from
Jun 6, 2018
Merged

Add "Cancel Running Test" status bar item #1218

merged 8 commits into from
Jun 6, 2018

Conversation

tylerstillwater
Copy link
Contributor

@tylerstillwater tylerstillwater commented Sep 16, 2017

Fixes #1047

This PR introduces two new pieces of functionality:

  1. Only one test can run at a time.
    a. Previously, if a user invoked a command to run a test while a test was already running, a second, entirely separate test instance would be started.
    b. This could cause some unexpected behavior, especially for tests that had a setup/teardown that both test instances were trying to use.
  2. A new "Cancel Running Test" status bar item appears at the bottom left of the status bar whenever a test is running.
    a. Clicking this status bar item will cancel the running test.

src/testUtils.ts Outdated

outputChannel.show(true);
}
return cancelRunningTest().then(success => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Things to consider. FYI currently more than one test can be run all together.

When the test on save hook enabled {"go.testOnSave": true}, then every time user save file, then it run the test. When one test takes to long then it make sense if it canceled only when the second test run for the same package. If we save file belongs to different package, then it doesn't make sense. This can be happen when we hit "Save All" then multiple test will run.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hadn't considered that. However, I'm not sure how we can have multiple running tests and also have the ability to cancel running tests. Perhaps keeping a list of all processes in flight and then iterating to cancel all of them?

I've never intentionally run multiple test instances in VSCode before, so the test-per-package-on-save never occurred to me. It seems the output would get very jumbled, though.

@ramya-rao-a I'd love your thoughts here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

am here am here...
Am prepping for an update at the moment, will get right back to this PR later this evening.

Thanks for your patience and sorry for the wait :(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, of course! Thank you for all that you do for the community! :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps keeping a list of all processes in flight and then iterating to cancel all of them?

This won't help in the "save all" scenario if you intend to cancel running tests before running a new test. Even though to the user, save all seems like a single event, the extension gets notified once for each document being saved which then triggers the test on the corresponding package.

How about having the cancel test as a command (just like you have now), but have it triggered only by the user and not before running a new test?

You will still have to keep track of all running tests and cancel each of them

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds like the best solution if we want to keep the functionality of running tests from multiple packages at once. I'll take a look at it when I have some time. Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tylerb @ramya-rao-a Probably there is a hack.
Extension react to the document save event. If we can delay this reaction for example for 1 second interval, capture all the events, after 1 second if we see more than one save events so run the test as one test session (run test only for affected packages).

Probably doesn't need to be 1sec, 500ms is enough.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, lets stick to the solution of the user cancelling the tests.

Save All triggering multiple processes also affects build/lint/vet. Let's tackle that in a separate PR

@ramya-rao-a
Copy link
Contributor

Slightly busy at work this week, I'll take a look and add my thoughts as soon as possible though.

@ramya-rao-a ramya-rao-a force-pushed the master branch 2 times, most recently from 7259f77 to f6936fa Compare October 2, 2017 20:31
@buyology
Copy link
Contributor

Any update on this? Would be great to have as some tests do not get timed out properly and then the only option is to kill vscode.

@ramya-rao-a ramya-rao-a force-pushed the master branch 3 times, most recently from 89e20b7 to 3d8a1f0 Compare November 4, 2017 19:44
@tylerstillwater
Copy link
Contributor Author

I'm still hoping to get this done soon taking all the discussion into account. Work has been crazy lately and I haven't had a chance to wrap this one up.

@buyology
Copy link
Contributor

@ramya-rao-a @tylerb — What's left to do on this one? It would be such a great feature to have.

@tylerstillwater
Copy link
Contributor Author

@buyology as per the discussion above, my change of "only allow one test to run at a time" disables some desired behavior. In order for this PR to be wrapped up, the following needs to happen:

1. Revert the "only allow a single test to run at a time" behavior
2. Add "track all tests in flight in a list" functionality
3. On user-initiated test cancellation, cancel all tests in the list.

This is still on my radar, but, unfortunately, pretty far down my list of priorities. I'm consumed by work at the moment.

@buyology
Copy link
Contributor

Thanks a lot for the summary 👍. If you don't mind I'll try and see if I can find some time to take a look at this and push this forward

@tylerstillwater
Copy link
Contributor Author

@buyology please do! I want this functionality pretty frequently myself.

@tylerstillwater
Copy link
Contributor Author

I've just rebased to clean up conflicts in my PR

@tylerstillwater
Copy link
Contributor Author

cc @buyology

Decided to take a break from work to just wrap this up. This PR now:

  1. When a test command is run, places the child process in an array of running tests
  2. When the test completes normally, removes the child process from the array.
  3. When the kill command is executed, iterates all running child processes and kills them.
  4. Runs the kill routine at VSCode shutdown to ensure all tests are cleaned up appropriately.

@ramya-rao-a please review

@tylerstillwater
Copy link
Contributor Author

I wanted to use SIGINT to allow go test to handle it and terminate gracefully, but it had no effect when I sent it. Is there something I'm missing? SIGKILL terminates the process immediately, but SIGINT gave no output and did not terminate the process.

@ramya-rao-a
Copy link
Contributor

@tylerb Work has been busy this month, I'll get to this PR later this week for sure

@tylerstillwater
Copy link
Contributor Author

@ramya-rao-a it took me 4 months to get to it myself. No worries!

@buyology
Copy link
Contributor

buyology commented Apr 12, 2018

@ramya-rao-a — can we please get this is in in the next release? It's such a great feature.

Just look at this sweetness ❤️

pebkac

@buyology
Copy link
Contributor

@ramya-rao-a — any update?

@tylerstillwater
Copy link
Contributor Author

@ramya-rao-a looks like this didn't make it into the latest release. Any particular reason for that? Anything you need me to do?

@ramya-rao-a
Copy link
Contributor

One reason I didnt add it to the current release was that I wanted to explore the new feature of notification msg for long running tasks which has the Cancel option.

See https://code.visualstudio.com/updates/v1_22#_extension-authoring

Thoughts?

@tylerstillwater
Copy link
Contributor Author

I didn't know that existed. I like that a lot more than what I have now.

@buyology
Copy link
Contributor

buyology commented Jun 4, 2018

Tbh, that progress box looks really intrusive. I really appreciate the elegancy and low keyness in this PR 👍

@tylerstillwater
Copy link
Contributor Author

I'm happy with either approach myself. Mine is done and ready. Perhaps it could be merged and then later updated to the new approach if it turns out that is a better way to do it?

@uudashr
Copy link
Contributor

uudashr commented Jun 5, 2018

There are two styles here

  1. When I use intellij or eclipse, the test are manually run.
  2. VSCode go, we can hook run test on save.

In my opinion, the first one will fit on the popup. I do care with the result whether it fail or succeed and willing to wait.
The second one, I don't want to wait, don't want to see the process, run it on background and notify me if there the test fail. Here we can put the cancel on the status bar.

So I think we can use both approach.

Copy link
Contributor

@ramya-rao-a ramya-rao-a left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tylerb Thanks a ton for your work on this and sorry for the delay.

I have left a few comments, please take a look.

src/testUtils.ts Outdated
if (!testconfig.background) {
let buildTags: string = testconfig.goConfig['buildTags'];
let args: Array<string> = ['test', ...testconfig.flags];
let testType: string = testconfig.isBenchmark ? 'Benchmarks' : 'Tests';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tylerb The above 3 variables do not really get used later. buildTags and args get re-assigned after this if block. Was this intentional?

The net affect is that when benchmarks are run,

  • the -benchmem flag is not used and so the memory related stats wont be shown
  • the -run=^$ flag is not used which means all the tests will be run when the user just wants to run the single benchmark

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what happened here. I'm updating it to reflect the current setup of this function as it exists in master.

src/testUtils.ts Outdated
} else {
args.push('-timeout', testconfig.goConfig['testTimeout']);
}
let args = ['test', ...testconfig.flags, '-timeout', testconfig.goConfig['testTimeout']];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will apply the timeout when running benchmarks as well. I am guessing when benchmarks are run, they should be allowed to take as much time as they need and shouldnt be bound with the timeout.

src/testUtils.ts Outdated
@@ -162,7 +180,7 @@ export function goTest(testconfig: TestConfig): Thenable<boolean> {

args.push(...targets);

let proc = cp.spawn(goRuntimePath, args, { env: testEnvVars, cwd: testconfig.dir });
let tp = cp.spawn(goRuntimePath, args, { env: testEnvVars, cwd: testconfig.dir, detached: true });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not clear on why we need to run this in a detached mode.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this was necessary in order to kill the process later when cancel was invoked. However, I may be wrong. I seem to recall seeing some odd behavior without it being detached, but I wrote this a long time ago.

src/testUtils.ts Outdated
outBuf.done();
errBuf.done();

if (code) {
outputChannel.appendLine(`Error: ${testType} failed.`);
outputChannel.appendLine('Error: Tests failed.');
} else if (signal === sendSignal) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for removing the use of the testType variable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason. Not sure why this got removed.

src/testUtils.ts Outdated
*/
export function cancelRunningTests(): Thenable<boolean> {
return new Promise<boolean>((resolve, reject) => {
let tp: cp.ChildProcess;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This variable is unused and need not be declared here.

@tylerstillwater
Copy link
Contributor Author

Thanks @ramya-rao-a - I'll take a look at all this and clean things up tomorrow.

@tylerstillwater
Copy link
Contributor Author

@ramya-rao-a I've pushed changes to address your review comments. Thanks!

@@ -266,6 +266,10 @@ export function activate(ctx: vscode.ExtensionContext): void {
showTestOutput();
}));

ctx.subscriptions.push(vscode.commands.registerCommand('go.test.cancel', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should expose this as a command as well. That would help users who are more inclined to use their keyboards and want to avoid the mouse

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed a commit to address this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

src/testUtils.ts Outdated
tp.kill(sendSignal);
});
// All processes are now dead. Empty the array to prepare for the next run.
testProcesses.splice(0, testProcesses.length);
Copy link
Contributor

@ramya-rao-a ramya-rao-a Jun 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Killed test processes go through line 239 where they are removed from the testProcesses array. Do we need to empty the array again here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, I do not know. I don't know if the kills are done in the background while the cancelRunningTests function continues to run. I wrote it such that we would have a clean state were that the case. Is that the case? I know little about the runtime here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not really sure..
But, there is no harm emptying the array at this point so we can keep it

@tylerstillwater
Copy link
Contributor Author

Thanks for all your help on this @ramya-rao-a! I'm definitely still learning.

@ramya-rao-a
Copy link
Contributor

My pleasure @tylerb! I am learning too :)

@ramya-rao-a ramya-rao-a merged commit 9faef72 into microsoft:master Jun 6, 2018
@buyology
Copy link
Contributor

buyology commented Jun 6, 2018

Great work on this! 🥇So nice to finally have this! 🌞

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants