Skip to content

Commit 6b5b2f8

Browse files
authored
Improve Testing Quality of Life (#144)
Lots of small fixes: 1. Alters the tests run on PRs and nightly. Full breakdown in filters.yaml. Brief summary below. a. If an individual linter or its subdir is changed, run tests (`[KGV, Latest]`) on that linter. b. If a test setup file in `tests/` is changed, run tests (`KGV`) on all linters. c. If `.trunk/trunk.yaml` is changed, run tests (`KGV`) on all linters (important to include trunk version behavior). d. If `linters/` or `readme.md` or `tests/` are changed, run repo tests. e. Nightlies will run all tests (`[Snapshots, Latest]`) based on plugin config in `main` AND all tests (`[Snapshots, Latest]`) on the latest tagged release (and upload the result) 2. Add `SANDBOX_DEBUG` env var that preserves and logs the sandbox test dir. 3. Expand the generate script for the helper action to include more pertinent information about writing/configuring tests. 4. Add some additional information to the `tests/readme.md`. I intend to eventually remove the logic that makes nightlies run on PRs that modify .github/workflows/nightly.yaml
1 parent 9131f96 commit 6b5b2f8

File tree

15 files changed

+225
-24
lines changed

15 files changed

+225
-24
lines changed

.github/filters.yaml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Run tests against all linters if the testing framework or trunk version changes.
2+
# These tests will be run with KnownGoodVersion.
3+
# e.g. `PLUGINS_TEST_LINTER_VERSION=KnownGoodVersion npm test linters`
4+
all-linters:
5+
- tests/driver/**
6+
- tests/reporter/**
7+
- tests/types/**
8+
- tests/utils/**
9+
- tests/index.ts
10+
- .trunk/trunk.yaml
11+
12+
# Run tests against specific linters if existing linters have been modified or updated.
13+
# These test will be run with KnownGoodVersion and Latest to verify linter integrity at the latest and fallback version.
14+
# Someone should not be able to add a new linter without verifying that it also works on the latest version.
15+
# e.g. `PLUGINS_TEST_LINTER_VERSION=[KnownGoodVersion,Latest] npm test linters/sqlfluff`
16+
linters:
17+
- linters/**
18+
19+
# Run tests against the health and configuration of the repo if any plugin definition
20+
# or testing framework change is made.
21+
# e.g. `npm test tests/repo_tests`
22+
repo-tests:
23+
- tests/**
24+
- linters/**
25+
- actions/**
26+
- readme.md
27+
- .trunk/trunk.yaml
28+
# Nightly jobs will run on all linters with Snapshots and Latest.
29+
# e.g. `PLUGINS_TEST_LINTER_VERSION=[Snapshots,Latest] npm test linters`

.github/workflows/nightly.yaml

+73-5
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ on:
1010
permissions: read-all
1111

1212
jobs:
13-
# TODO(Tyler): Forward json outputs from job
14-
# Run tests against all linters for snapshots and latest version
15-
linter_tests:
13+
# Run tests against all linters for snapshots and latest version as they exist on main
14+
# This job is used to diagnose plugin config health in advance of a release
15+
linter_tests_main:
1616
name: Plugin Tests
1717
runs-on: ${{ matrix.os }}
1818
timeout-minutes: 60
@@ -24,7 +24,75 @@ jobs:
2424
steps:
2525
- name: Checkout
2626
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
27-
# TODO(Tyler): Iron out ref for tests
27+
28+
- name: Cache tool downloads
29+
uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
30+
with:
31+
path: /tmp/plugins_testing_download_cache
32+
# No need to key on trunk version unless we change how we store downloads.
33+
key: trunk-${{ runner.os }}
34+
35+
- name: Delete cache
36+
# For now, avoid deleting cache on pull request changes to nightly. This improves PR experience.
37+
if: env.TRIGGER != 'pull_request'
38+
run: |
39+
if [ -d "/tmp/plugins_testing_download_cache" ]
40+
then
41+
tmp_dir=/tmp/${GITHUB_RUN_ID}-${GITHUB_RUN_NUMBER}-${GITHUB_RUN_ATTEMPT}
42+
mv "/tmp/plugins_testing_download_cache" ${tmp_dir}
43+
chmod -R u+w ${tmp_dir}
44+
rm -rf ${tmp_dir}
45+
fi
46+
shell: bash
47+
48+
- name: Linter Tests
49+
uses: ./.github/actions/linter_tests
50+
with:
51+
linter-version: ${{ matrix.linter-version }}
52+
53+
# Run tests against all linters for snapshots and latest version as they exist in latest release
54+
# This job is used to update the list of validated versions
55+
linter_tests_release:
56+
name: Plugin Tests
57+
runs-on: ${{ matrix.os }}
58+
timeout-minutes: 60
59+
strategy:
60+
fail-fast: false
61+
matrix:
62+
linter-version: [Snapshots, Latest]
63+
os: [ubuntu-latest, macos-latest]
64+
steps:
65+
- name: Retrieve git history
66+
uses: actions/checkout@v3
67+
with:
68+
fetch-depth: 0
69+
70+
# This assumes that any changes on main since the last release are backwards compatible
71+
# in terms of allowing existing linter tests to run.
72+
- name: Preserve test runner latest behavior
73+
run: |
74+
cp -r tests tests.bak
75+
cp package.json package.json.bak
76+
cp package-lock.json package-lock.json.bak
77+
78+
- name: Get Latest Release
79+
id: get-release
80+
uses: WyriHaximus/github-action-get-previous-tag@385a2a0b6abf6c2efeb95adfac83d96d6f968e0c # v1.3.0
81+
with:
82+
# only use releases tagged v<semver>
83+
prefix: v
84+
85+
- name: Checkout
86+
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
87+
with:
88+
ref: ${{ steps.get-release.outputs.tag }}
89+
clean: false
90+
91+
- name: Overwrite test runners with latest behavior
92+
run: |
93+
mv tests.bak tests
94+
mv package.json.bak package.json
95+
mv package-lock.json.bak package-lock.json
2896
2997
- name: Cache tool downloads
3098
uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
@@ -62,7 +130,7 @@ jobs:
62130

63131
upload_test_results:
64132
name: Upload Test Results
65-
needs: linter_tests
133+
needs: linter_tests_release
66134
runs-on: ubuntu-latest
67135
# Still run on test failure
68136
if: always()

.github/workflows/pr.yaml

+68
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,64 @@ jobs:
2727
- name: Trunk Check
2828
uses: trunk-io/trunk-action@9cf65e08e822e9842fd9ef7ed2a2bd9092de0986 # v1.0.6
2929

30+
detect_changes:
31+
name: Detect changed files
32+
runs-on: ubuntu-latest
33+
timeout-minutes: 5
34+
35+
outputs:
36+
linters: ${{ steps.filter.outputs.linters }}
37+
repo-tests: ${{ steps.filter.outputs.repo-tests }}
38+
# "linters" if ${{ steps.filter.outputs.all-linters }} is 'true'
39+
all-linters: ${{ steps.post-filter.outputs.out }}
40+
# shortened paths to linter subdirs
41+
linters-files: ${{ steps.post-filter-paths.outputs.out }}
42+
43+
steps:
44+
- name: Checkout
45+
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
46+
47+
- name: Determine upstream
48+
run: |
49+
head_sha=$(git rev-parse HEAD)
50+
git -c protocol.version=2 fetch -q \
51+
--no-tags \
52+
--no-recurse-submodules \
53+
--depth=2 \
54+
origin "${head_sha}"
55+
upstream=$(git rev-parse HEAD^1)
56+
echo "TEST_UPSTREAM=${upstream}" >>"${GITHUB_ENV}"
57+
58+
- name: Detect changed paths
59+
uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
60+
id: filter
61+
with:
62+
base: ${{ env.TEST_UPSTREAM }}
63+
filters: .github/filters.yaml
64+
list-files: shell
65+
66+
- name: Suggest all linter tests
67+
id: post-filter
68+
if: steps.filter.outputs.all-linters
69+
run: echo "out=linters" >> "$GITHUB_OUTPUT"
70+
71+
- name: Suggest normalized individual linter paths
72+
id: post-filter-paths
73+
if: steps.filter.outputs.linters
74+
run: |
75+
echo ${{steps.filter.outputs.linters_files}} |
76+
grep -oP "\Klinters/.*?(?=/)" |
77+
tr '\n' ' ' |
78+
echo "out=$(cat)" >> "$GITHUB_OUTPUT"
79+
3080
# Run tests against all linters for known_good_version and latest version
3181
linter_tests:
3282
name: Plugin Tests
3383
runs-on: ${{ matrix.os }}
84+
needs: detect_changes
85+
if:
86+
needs.detect_changes.outputs.linters == 'true' || needs.detect_changes.outputs.all-linters ==
87+
'linters'
3488
timeout-minutes: 60
3589
strategy:
3690
fail-fast: false
@@ -48,11 +102,25 @@ jobs:
48102
key: trunk-${{ runner.os }}
49103

50104
- name: Linter Tests
105+
# Run tests using KnownGoodVersion with any modified linters and conditionally all linters
51106
uses: ./.github/actions/linter_tests
52107
with:
53108
linter-version: KnownGoodVersion
109+
append-args:
110+
${{ needs.detect_changes.outputs.all-linters }} ${{
111+
needs.detect_changes.outputs.linters-files }}
112+
113+
- name: Latest Tests Latest
114+
# Run tests on Latest with any modified linters (see filters.yaml). Don't run when cancelled.
115+
if: ${{ (failure() || success()) && needs.detect_changes.outputs.linters == 'true' }}
116+
uses: ./.github/actions/linter_tests
117+
with:
118+
linter-version: Latest
119+
append-args: ${{needs.detect_changes.outputs.linters-files }}
54120

55121
# Run repo healthcheck tests
56122
repo_tests:
57123
name: Repo Tests
124+
needs: detect_changes
125+
if: needs.detect_changes.outputs.repo-tests == 'true'
58126
uses: ./.github/workflows/repo_tests.reusable.yaml

.github/workflows/repo_tests.reusable.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535

3636
- name: Run repo tests
3737
run: |
38-
PATH=$(npm bin):$PATH npm test --ci tests
38+
PATH=$(npm bin):$PATH npm test --ci tests/repo_tests
3939
env:
4040
PLUGINS_TEST_CLI_VERSION: ${{ inputs.cli-version }}
4141
PLUGINS_TEST_CLI_PATH: ${{ inputs.cli-path }}

.trunk/trunk.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ plugins:
1111
sources:
1212
- id: trunk
1313
uri: https://github.com/trunk-io/plugins
14-
ref: 454583aa8bb4d092db343c7c4a71a72a19938768
14+
ref: 454583aa8bb4d092db343c7c4a71a72a19938768 # run the plugins repo at its own latest commit
1515

1616
runtimes:
1717
enabled:
@@ -67,7 +67,7 @@ actions:
6767
description: Run tests on plugin configuration and documentation
6868
runtime: node
6969
packages_file: package.json
70-
run: npm test tests/
70+
run: npm test tests/repo_tests
7171
triggers:
7272
- git_hooks: [pre-push]
7373

linters/sqlfluff/sqlfluff.test.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import { linterCheckTest, linterFmtTest, TestCallback } from "tests";
44
// trunk check linters/sqlfluff/test/basic_check.in.sql --force --filter=sqlfluff --output=json
55
linterCheckTest({ linterName: "sqlfluff", namedTestPrefixes: ["basic_check"] });
66

7-
// Due to sqlfluff's fix subcommand being disabled by default, we need to manually enable it in our test's
8-
// trunk.yaml.
7+
// Due to sqlfluff's fix subcommand being disabled by default, we need to manually enable it in the trunk.yaml.
98
const fmtCallbacks: TestCallback = (driver) => {
109
const trunkYamlPath = ".trunk/trunk.yaml";
1110
const currentContents = driver.readFile(trunkYamlPath);

security.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ Instead we recommend all users upgrade to the latest release as it comes out.
1111

1212
## Reporting a Vulnerability
1313

14-
Please reposrt (suspected) security vulnerabilities to [email protected]. You will receive a
15-
response from the team within 48 hours. If the issue is confirmed, we will create a new release as
16-
soon as possible.
14+
Please report (suspected) security vulnerabilities to [email protected]. You will receive a response
15+
from the team within 48 hours. If the issue is confirmed, we will create a new release as soon as
16+
possible.

tests/driver/index.ts

+11
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,17 @@ export class TrunkDriver {
218218
tearDown() {
219219
this.debug("Cleaning up %s", this.sandboxPath);
220220
const trunkCommand = ARGS.cliPath ?? "trunk";
221+
222+
// Preserve test directory if `SANDBOX_DEBUG` is truthy.
223+
if (ARGS.sandboxDebug) {
224+
execFileSync(trunkCommand, ["daemon", "shutdown"], {
225+
cwd: this.sandboxPath,
226+
env: executionEnv(this.getSandbox()),
227+
});
228+
console.log(`Preserving test dir ${this.getSandbox()} for linter ${this.linter ?? "N/A"}`);
229+
return;
230+
}
231+
221232
execFileSync(trunkCommand, ["deinit"], {
222233
cwd: this.sandboxPath,
223234
env: executionEnv(this.getSandbox()),

tests/readme.md

+17-7
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,20 @@ npm test ${path_to_linter_subdir}
6363
Then, verify that the generated snapshot file includes the results you would expect (e.g. an Object
6464
with several fileIssues, no taskFailures).
6565

66+
For context, the general test execution is as follows:
67+
68+
1. Create a sandbox testing directory by copying a linter's subdirectory and its `test_data`.
69+
2. Initialize a base .trunk/trunk.yaml in the sandbox with the version in
70+
[.trunk/trunk.yaml](../.trunk/trunk.yaml).
71+
3. Run `trunk check enable <linter>`.
72+
4. Run `trunk check` or `trunk fmt` on files with the `<name>.in.<extension>` syntax.
73+
6674
### Linter Versioning
6775
6876
The first time a test runs, it will attempt to run against a linter's `known_good_version`. This
69-
snapshot is required for CI mirrors the behavior in CI and is used to validate that a linter runs as
70-
expected across multiple versions. Subsequent test runs will only run against its latest version
71-
unless otherwise specified (See [Environment Overrides](#environment-overrides)).
77+
snapshot mirrors the behavior in CI and is used to validate that a linter runs as expected across
78+
multiple versions. Subsequent test runs will only run against its latest version unless otherwise
79+
specified (See [Environment Overrides](#environment-overrides)).
7280

7381
If this causes the test to fail when run with the latest version, this is most likely because there
7482
are discrepancies in the linter output across versions. Rather than running `npm test -- -u`,
@@ -129,10 +137,12 @@ include:
129137
- `PLUGINS_TEST_UPDATE_SNAPSHOTS` if `true`, tells tests to use an exact match of the linter version
130138
when checking the output. Only set this if a linter has introduced a output variation with a
131139
version change.
140+
- `SANDBOX_DEBUG` if `true`, prevents sandbox test directories from being deleted, and logs their
141+
path for additional debugging.
132142

133143
### CI
134144

135-
PRs will run 5 types of tests across both ubuntu and macOS:
145+
PRs will run 5 types of tests across both ubuntu and macOS as applicable:
136146

137147
1. Enable and test all linters with their `known_good_version`, if applicable. To replicate this
138148
behavior, run: `PLUGINS_TEST_LINTER_VERSION=KnownGoodVersion npm test`. If the
@@ -146,9 +156,9 @@ PRs will run 5 types of tests across both ubuntu and macOS:
146156

147157
### Debugging
148158

149-
Tests normally complete in less than 1 minute. They may take up to 5 minutes or so if the dependency
150-
cache is empty (linters need to be downloaded and installed to run the linter tests). Subsequent
151-
runs will not experience this delay.
159+
Individual tests normally complete in less than 1 minute. They may take up to 5 minutes or so if the
160+
dependency cache is empty (linters need to be downloaded and installed to run the linter tests).
161+
Subsequent runs will not experience this delay.
152162

153163
Errors encountered during test runs are reported through the standard `console`, but additional
154164
debugging is provided using [debug](https://www.npmjs.com/package/debug). The namespace convention
File renamed without changes.
File renamed without changes.
File renamed without changes.

tests/types/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ export interface TestingArguments {
3434
/** Whether tests should create new snapshot files if snapshots already exist
3535
* even if a match is found. */
3636
dumpNewSnapshot: boolean;
37+
/** Prevents the deletion of sandbox test dirs. */
38+
sandboxDebug: boolean;
3739
}
3840

3941
/**** Landing state ****/

tests/utils/index.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,24 @@ const normalizePath = (value?: string): string | undefined => {
4747
* - PLUGINS_TEST_CLI_PATH specifies an alternative path to a trunk binary.
4848
* - PLUGINS_TEST_LINTER_VERSION specifies a linter version semantic (see `parseLinterVersion`).
4949
* - PLUGINS_TEST_UPDATE_SNAPSHOTS uses the snapshot from the enabled version of the linter, creating a new snapshot if necessary.
50+
* - SANDBOX_DEBUG prevents test directories from being deleted.
5051
*/
5152
export const ARGS: TestingArguments = {
5253
cliVersion: coalesceString(process.env.PLUGINS_TEST_CLI_VERSION),
5354
cliPath: normalizePath(process.env.PLUGINS_TEST_CLI_PATH),
5455
linterVersion: parseLinterVersion(process.env.PLUGINS_TEST_LINTER_VERSION ?? ""),
5556
dumpNewSnapshot: Boolean(process.env.PLUGINS_TEST_UPDATE_SNAPSHOTS),
57+
sandboxDebug: Boolean(process.env.SANDBOX_DEBUG),
5658
};
5759
// TODO(Tyler): PLUGINS_TEST_LINTER_VERSION is a string version, we should mandate that a test filter is applied
5860
// to avoid accidental enables.
59-
if (ARGS.cliVersion || ARGS.cliPath || ARGS.linterVersion || ARGS.dumpNewSnapshot) {
61+
if (
62+
ARGS.cliVersion ||
63+
ARGS.cliPath ||
64+
ARGS.linterVersion ||
65+
ARGS.dumpNewSnapshot ||
66+
ARGS.sandboxDebug
67+
) {
6068
Debug("Tests").extend("Global")("%o", ARGS);
6169
}
6270

tools/linter-test-helper/generate

+9-3
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,20 @@ lint:
1919
"""
2020

2121
INITIAL_TEST_CONTENTS = """import { linterCheckTest, linterFmtTest } from "tests";
22-
// Use if your tool is a linter
22+
// Uncomment and use if your tool is a linter
2323
// linterCheckTest({ linterName: "*{}*" });
2424
25-
// Use if your tool is a formatter
25+
// Uncomment and use if your tool is a formatter
2626
// linterFmtTest({ linterName: "*{}*" });
2727
28+
// Guidelines for configuring tests:
29+
// - By default, linters and formatters will only run on files with syntax `<name>.in.<extension>`
30+
// - You can customize test setup using the `preCheck` callback (see git_diff_check.test.ts and golangci_lint.test.ts)
31+
// - You can specify additional customization using the `customLinterCheckTest and customLinterFmtTest` helpers
32+
// - Additional information on test setup can be found in tests/readme.md
33+
//
2834
// If you are unable to write a test for this linter, please document why in your PR, and add
29-
// it to the list in tests/test_coverage_test.ts
35+
// it to the list in tests/repo_tests/test_coverage_test.ts
3036
"""
3137

3238

0 commit comments

Comments
 (0)