Skip to content
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

Merged
merged 22 commits into from
Mar 9, 2020
Merged

Implement QL Test support #173

merged 22 commits into from
Mar 9, 2020

Conversation

dbartol
Copy link
Contributor

@dbartol dbartol commented Nov 20, 2019

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 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. This is now implemented using 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 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 availablewe use codeql resolve tests. 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 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.

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.
@lgtm-com
Copy link

lgtm-com bot commented Nov 20, 2019

This pull request introduces 2 alerts when merging 444aca3 into a559404 - view on LGTM.com

new alerts:

  • 2 for Unused variable, import, function or class

@dbartol
Copy link
Contributor Author

dbartol commented Nov 21, 2019

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.

@dbartol dbartol marked this pull request as ready for review November 21, 2019 00:21
@@ -8,8 +8,7 @@
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceRoot}/dist/vscode-codeql",
"--disable-extensions"
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

@adityasharad adityasharad left a 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",
Copy link
Contributor

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.

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 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.

extensions/ql-vscode/package.json Outdated Show resolved Hide resolved
},
"codeQL.tests.numberOfThreads": {
"scope": "window",
"type": "integer",
Copy link
Contributor

Choose a reason for hiding this comment

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

Default to 1?

Copy link
Contributor Author

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`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* 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`.

Copy link
Contributor Author

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('__')) {
Copy link
Contributor

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/package.json Outdated Show resolved Hide resolved
@dbartol dbartol added the enhancement New feature or request label Feb 15, 2020
export interface ResolvedQLPacks {
[index: string]: string[];
}

Copy link
Contributor

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops. Fixed.

@dbartol dbartol changed the title Implement QL Test support (using odasa for now) Implement QL Test support Feb 18, 2020
Copy link
Contributor

@jcreedcmu jcreedcmu left a 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?

@jcreedcmu jcreedcmu merged commit 9377279 into github:master Mar 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants