-
Notifications
You must be signed in to change notification settings - Fork 189
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
Implement QL Test support #173
Conversation
The PR contains the initial implementing of QL Test support in CodeQL for Visual Studio Code. Because QL Test support isn't quite ready in the CLI yet, this PR uses `odasa` to run the tests for now. As CLI support comes online, it should be straightforward to swap out the implementation to use the CLI. The treeview UI for the tests is implemented via the `hbenl.vscode-test-explorer` extension. This extension is open source, and appears to be actively maintained. It's used by a couple dozen existing extensions for tests for various languages. The extension doesn't really do anything on its own, so taking it as a dependency isn't introducing any unwanted UI clutter. Note that I did have to remove the `--disable-extensions` argument from `launch.json`, because otherwise the test explorer extension gets disabled, preventing our own extension from loading. The UI will display a root node for each QL pack that contains tests, with the actual test directories and files as descendants of that root node. We consider only those QL packs in the workspace; QL packs on the default CodeQL search path are ignored. We use `codeql resolve qlpacks` to find the packs, and then watch all `qlpack.yml` files in the workspace for changes in order to refresh the pack discovery when necessary. Ideally, we'd have the CLI return a set of path patterns to watch, but for now the current implementation works fine. To discover the tests within a given pack, we walk the pack's directory tree manually for now, until the relevant CLI command is available. Because we do not yet have a mechanism in `qlpack.yml` to specify whether or not the pack contains tests, we assume that any pack whose name ends with "-tests" to contain nothing but tests, and any other pack to contain no tests. This is sufficient for the tests in the QL repo. As with QL pack discovery, we watch the file system for changes in `.ql` and `.qlref` files in order to refresh the tree of tests if anything changes. To actually run the tests, we just invoke `odasa qltest` with the appropriate arguments. This code is pretty much a straight copy-and-paste from the repo where I've had a private version of QL Test support for several months. Once we can run tests via the CLI, this will all be deleted. The `test-ui.ts` file implements a couple of additional commands for the context menu of the test treeview. You can accept the output of a failing test (copying the `.actual` file to the `.expected` file), and you can bring up a diff view of the `.expected` and `.actual` files). This PR includes a couple of related utility classes. `UIService` makes it a little easier to implement a service that handles VS Code commands. `Discovery` is a base class that handles most of the work that is shared between the different kinds of discovery that we do, like avoiding running multiple discovery operations simultaneously if we get a storm of file change notifications.
This pull request introduces 2 alerts when merging 444aca3 into a559404 - view on LGTM.com new alerts:
|
I've added a much better error message when trying to run tests without Semmle Core configured. Since we may be waiting a while for CLI test support, I think we should merge this PR now rather than let it rot while we wait. |
@@ -8,8 +8,7 @@ | |||
"request": "launch", | |||
"runtimeExecutable": "${execPath}", | |||
"args": [ | |||
"--extensionDevelopmentPath=${workspaceRoot}/dist/vscode-codeql", | |||
"--disable-extensions" |
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 don't quite understand the reason for removing --disable-extensions
? I thought we had it in here to ensure that integration test failures couldn't be because some other extension was confusing things.
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.
Our extension now depends on the "VS Code Test Explorer" extension. If we launch VS Code with --disable-extensions
, it disables the "VS Code Test Explorer" extension, and therefore refuses to load our own extension due to the disabled dependency.
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.
First pass, still need to look into the watching/discovery code more carefully.
"activationEvents": [ | ||
"onLanguage:ql", | ||
"onView:codeQLDatabases", | ||
"onView:codeQLQueryHistory", | ||
"onView:test-explorer", |
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.
Do we need this? If you have the test explorer open but no CodeQL workspace then I'm not sure we need to activate yet.
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 we need it for the same reason we need the other onView:
events: If I open a workspace that contains CodeQL tests, but have not yet opened a .ql file, I should still be able to browse and run my tests.
}, | ||
"codeQL.tests.numberOfThreads": { | ||
"scope": "window", | ||
"type": "integer", |
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.
Default to 1?
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 to be 1, allowed range [1, 1024], just like the number of threads for queries.
import { DisposableObject } from 'semmle-vscode-utils'; | ||
|
||
/** | ||
* A node in the tree of tests. This will be either a `QLTestDirector` or a `QLTestFile`. |
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.
* A node in the tree of tests. This will be either a `QLTestDirector` or a `QLTestFile`. | |
* A node in the tree of tests. This will be either a `QLTestDirectory` or a `QLTestFile`. |
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
switch (path.extname(fullPath).toLowerCase()) { | ||
case '.ql': | ||
case '.qlref': { | ||
if (!path.basename(fullPath).startsWith('__')) { |
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.
What is __
for?
extensions/ql-vscode/src/cli.ts
Outdated
export interface ResolvedQLPacks { | ||
[index: string]: 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.
Seems to be used in src/qlpack-discovery.ts
, actually
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.
Oops. Fixed.
odasa
for now)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.
General comment: If I have run quick query previously on a workspace, a directory 'Quick Query' appears in the test panel with no tests in it. I don't know if you expected this or not --- it is the case that the directory has a qlpacks.yml
file in it, so it makes sense that it shows up during qlpack discovery. Maybe we should cull directories that have no tests?
The PR contains the initial implementing of QL Test support in CodeQL for Visual Studio Code (https://github.com/github/pe-security-codeql/issues/28).
Because QL Test support isn't quite ready in the CLI yet, this PR usesThis is now implemented usingodasa
to run the tests for now. As CLI support comes online, it should be straightforward to swap out the implementation to use the CLI.codeql tests run
.The treeview UI for the tests is implemented via the
hbenl.vscode-test-explorer
extension. This extension is open source, and appears to be actively maintained. It's used by a couple dozen existing extensions for tests for various languages. The extension doesn't really do anything on its own, so taking it as a dependency isn't introducing any unwanted UI clutter. Note that I did have to remove the--disable-extensions
argument fromlaunch.json
, because otherwise the test explorer extension gets disabled, preventing our own extension from loading.The UI will display a root node for each QL pack that contains tests, with the actual test directories and files as descendants of that root node. We consider only those QL packs in the workspace; QL packs on the default CodeQL search path are ignored. We use
codeql resolve qlpacks
to find the packs, and then watch allqlpack.yml
files in the workspace for changes in order to refresh the pack discovery when necessary. Ideally, we'd have the CLI return a set of path patterns to watch, but for now the current implementation works fine.To discover the tests within a given pack,
we walk the pack's directory tree manually for now, until the relevant CLI command is availablewe usecodeql resolve tests
. Because we do not yet have a mechanism inqlpack.yml
to specify whether or not the pack contains tests, we assume that any pack whose name ends with "-tests" to contain nothing but tests, and any other pack to contain no tests. This is sufficient for the tests in the QL repo. As with QL pack discovery, we watch the file system for changes in.ql
and.qlref
files in order to refresh the tree of tests if anything changes.To actually run the tests, we just invoke
codeql test run
with the appropriate arguments.The
test-ui.ts
file implements a couple of additional commands for the context menu of the test treeview. You can accept the output of a failing test (copying the.actual
file to the.expected
file), and you can bring up a diff view of the.expected
and.actual
files).This PR includes a couple of related utility classes.
UIService
makes it a little easier to implement a service that handles VS Code commands.Discovery
is a base class that handles most of the work that is shared between the different kinds of discovery that we do, like avoiding running multiple discovery operations simultaneously if we get a storm of file change notifications.