-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add test explorer #16662
feat: Add test explorer #16662
Conversation
b86d6b3
to
348847e
Compare
@ShuiRuTian Can you please review this? You can probably detect its problems since you have implemented this functionality one time :) |
348847e
to
69bf993
Compare
Hi @HKalbasi Thanks for the ping. I have not reviewed the details of this PR, and I even forgot some details about my PR, so the questions might be stupid.
I would try to pick some time to review this PR in detail. |
2dcd1c3
to
5358443
Compare
@ShuiRuTian thanks for your comment.
My understanding from #16515 was that your PR was closed since it was heavy on the client side, which is not desired. Specially about the #3601 (comment) the part that this PR differs from it is that it runs the
I intentionally deferred it to the future. Running the debug on the server is challenging (but is possible) and running it on the client is against the point of this PR, and test explorer is very useful even without debugging (one can double click on the test in the test explorer, and then use the old debug lens) so I ignored it for now.
I added it in my last commit.
I don't know exactly what is this. If you hint me about it, I can try to implement it.
I don't know much about this one either. When should it be called, and what is its effect in the UI?
It doesn't reuse the runnables lsp extension, to keep the client side logic simpler. The runnables lsp extension is not a holy thing to keep it as is, and I think a polished version of this new extension set can replace (most of) the runnables extension in future when it gains support from more clients. Tangentially, I think in some point we can retire the code lenses for run and debugging tests in favor of the client native UI.
At the protocol level, it can be any module, and client side implementation can handle that, but the server side implementation currently work at the crate level, and return all tests in the crates of the open files and for resolve request. It is not hard to fix it, but it works well enough on the r-a repo so I don't think it is a problem and we can always fix it if it becomes one.
Thank you! |
Oops, my bad, I forgot to explain some terms.
This is a "refresh" icon. TestController has a method called "refreshHandler", which would be called. This feature is useful when something goes wrong(according to my experience, mainly because sync issues). We could rebuild everything.
This means the tests user chooses to run, but they might not be started yet. Just call them immediately when user click "run" button. TestRun has enqueued method. To know the status of tests, you could run command with
Agree, but as you said, it might be not easy to add Debug support. And, according to my experience, again, it might need totally refactor when you need some new features. I reimplemented the whole world once. Also, I am kind of curious what it looks like now. I implemented some feature to try to make it look more naturally:
|
a594e1a
to
aa55695
Compare
I added some icons, basic debug support, and refresh handler. About enqueued status, my cargo only emits the started event. Do you mean to emit enqueued in that situation? Or there is some other events gated behind a flag (I tried
I omitted this one for the simplicity of the implementation, but it can be easily added in a separate PR. |
☔ The latest upstream changes (presumably #16704) made this pull request unmergeable. Please resolve the merge conflicts. |
I'm going to merge this, I think this is in the scope of the project, since any other extensions implementing this functionality needs to either ask cargo or r-a to provide it, both are not ideal, and this PR is small enough, specially client side, to be included in the main extension. And this PR is certainly not perfect, but we can incrementally improve it and we shouldn't let perfect becomes the enemy of good. @bors r+ |
☀️ Test successful - checks-actions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've only read the documentation, so my "review" is not well informed. Sorry.
range?: lc.Range | undefined; | ||
// A human readable name for this test | ||
label: string; | ||
icon: "package" | "module" | "test"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling this kind
would be more in line with the LSP specification. A client might want to something else with this information than displaying it as an icon.
For example, see the definition of CompletionItem
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in #16794
**Request:** `RunTestParams` | ||
|
||
```typescript | ||
interface DiscoverTestParams { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a copy'n'paste error? DiscoverTestParams
is already defined in line 395. This is probably RunTestParams
. I also assume the experimental/runTest request is sent from the client to the server. But what how should the client specify include
and exclude
. I'm guessing these are lists of TestItem ids, right? Is it okay to specify both lists at the same time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in #16794
**Notification:** `ChangeTestStateParams` | ||
|
||
```typescript | ||
type TestState = { tag: "failed"; message: string } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is message
a plain string or markdown formatted? What happens when the client supports colorDiagnosticOutput?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is the stderr of the test, and it usually has no color unless the program explicitly prints some ansi colored text, which in this case I think it is reported as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be helpful to extend the documentation explaining that the message is the standard error of the test.
// request for simple execution, but for more complex execution forms | ||
// like debugging, this field is useful. | ||
runnable?: Runnable | undefined; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for completeness (and when the client desynchronizes) would it make sense to include a state: TestState
field as well? With possible additional states like: scheduled
(scheduled to run) and initial
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the client desynchronization happens frequently? The server does not store the test state currently, and it only report it to the client. In the vscode I think it stores the previous results independent of the server, does it solve this problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Desynchronization is rare, and it is usually a result of a bug. But these bugs are hard to track down, so any additional info helps to find them. At any rate, the server does seem to store something about the tests otherwise how it can detect changes in existing tests and send the experimental/discoveredTests notification.
Maybe TestItem should not contain its state if that's to hard to do, but a queue-position
would be definitely useful showing how many tests are before it if rust-analyzer scheduled the test to run.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there is value in keeping the discovery phase and running phase separate. They are separate in the vscode api, and in the r-a case, in the discovery phase the server uses its knowledge but in the running phase it just act as a proxy between cargo and the client. So I think not adding test state and queue position in the discovery related requests is good. But maybe maybe we can add more information to the run related requests for the desynchronization problem. But maybe if it is a rare and bug related event, then the user can just tolerate it rerun the tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably. Thanks for this and other clarifications and updates of the documentation.
I did not image this PR would be merged so quickly... I am still curious what does it looks like for now, anyway, I could try next publishment. |
Me neither. I am not too happy with the hack to get around a cargo limitation either in this honestly, r-a already has way too much tech debt as is and this is just adding on to it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't looked at the actual logic here yet, unsure when I'll get to that since I'll need to brush up on what was said in #3601 designwise to compare.
@@ -0,0 +1,25 @@ | |||
//! Currently cargo does not emit crate name in the `cargo test --format=json`, which needs to be changed. This |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then we should get that fixed in cargo instead of creating this mess here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will try to fix it in cargo, By the way @ShuiRuTian did you had better solution to this in your PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what here want to do.
If it's trying to find the crate of running tests, it's not a big problem in my PR. Because we do have the entire logic test tree(creates-testkinds-modules-tests) and we only allows one test to be run meanwhile, so it's easy to get the crate of the test that user clicked by calling get parent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aha. This PR handles running multiple tests so it hits this problem.
It seems there is an effort in upstream (see rust-lang/testing-devex-team#1 and rust-lang/rfcs#3558) about reworking the test json output that will hopefully fix this problem.
parent?: string | undefined; | ||
textDocument?: lc.TextDocumentIdentifier | undefined; | ||
range?: lc.Range | undefined; | ||
runnable?: Runnable | undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, do we have runnable
at the first commit?
The info in Runnable is rich, I believe it already tells range
, textDocument
, and parent
. It would be kind of confused if there is no single truth of source.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't tell parent
, but it tells range
and textDocument
. I will remove the duplicate fields of runnable here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up keeping those fields, since some of them should be kept in sync with the old runnables in order to function correctly without breaking the old runnables, but are not ideal for the test explorer usage. And it makes the implementation for clients that already implement the runnable extension simpler.
runnable?: Runnable | undefined; | ||
}; | ||
export type DiscoverTestResults = { tests: TestItem[]; scope: string[] }; | ||
export type TestState = { tag: "failed"; message: string } | { tag: "passed" } | { tag: "started" }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At lease there is also cancel
and ignore
state. BSP is a good exmple.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in #16794. Neither cargo nor the vscode api don't have anything equivalent to cancel I think, so I omitted it for now.
@@ -103,6 +105,10 @@ export class Ctx implements RustAnalyzerExtensionApi { | |||
) { | |||
extCtx.subscriptions.push(this); | |||
this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); | |||
this.testController = vscode.tests.createTestController( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add an option to control whether the feature is enabled? The default might be true
(although it's kind of aggressive for me, because the API are all experimental), but an option is a good escape hatch if there is something wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, config (defaulted to false) and a capability is the least we should do here. #16773
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why should the default be false? Does the presence of this feature interfere with normal operation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is hot of the press, it might have issues we don't know about and we don't know the perf impact yet (this is the important bit imo, especially if someone doesn't make use of it, we shouldn't be wasting cpu cycles on the feature). Turning it off by default (and then stating that in the changelog how to enable) seems like the better starting experience, I reckon (at least judging from the issue) that enough people are interested in this and enable to it to give us relevant testing feedback.
Some minor changes in the test explorer lsp extension followup #16662 cc `@nemethf` `@ShuiRuTian`
This PR implements the vscode testing api similar to #14589, this time using a set of lsp extensions in order to make it useful for clients other than vscode, and make the vscode client side logic simpler (its now around ~100 line of TS code)
Fix #3601