Skip to content

Commit d78037d

Browse files
redsun82Copilot
andcommitted
Rust: Add manual regression test for dbscheme upgrade
Adds a test directory with queries that verify properties are preserved when upgrading databases from rust-analyzer 0.0.301 to 0.0.328. This is a one-off manual test (not yet in CI), but could serve as the foundation for a general upgrade testing strategy. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a2ecf65 commit d78037d

9 files changed

Lines changed: 300 additions & 0 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.testproj/
2+
*.actual
3+
*.log
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Rust upgrade preservation test
2+
3+
This directory contains a manual regression test for the Rust dbscheme upgrade from rust-analyzer 0.0.301 to 0.0.328.
4+
5+
It is **not yet checked by CI**. The test has to be run manually because it requires building an old extractor to create an old-schema database first.
6+
7+
## Directory structure
8+
9+
- `old/`: Test query for the **old** schema, showing fields that will be upgraded
10+
- `new/`: Test query and sources for the **new** schema after upgrade
11+
12+
## Running the test
13+
14+
From anywhere in the repository:
15+
16+
```bash
17+
rust/ql/lib/upgrades/66a489863649185f4a9770f894505803059a1312/test/run-test.sh
18+
```
19+
20+
Or override the old commit if needed:
21+
22+
```bash
23+
OLD_COMMIT=<commit> rust/ql/lib/upgrades/.../test/run-test.sh
24+
```
25+
26+
The script will:
27+
1. Copy test files to a temp directory
28+
2. Stash uncommitted changes and checkout the old commit
29+
3. Build the old extractor with `bazel run //rust:install`
30+
4. Create an old-schema database with `codeql test run`
31+
5. Restore your branch and pop the stash
32+
6. Upgrade the database to the new schema
33+
7. Run the preservation test on the upgraded database
34+
35+
If the expected output needs to be refreshed after an intentional query change, manually run the final `codeql test run` with `--learn`.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
formatArgNamePreserved
2+
| upgrade_shapes.rs:22:37:22:41 | FormatArgsArg | upgrade_shapes.rs:22:37:22:37 | FormatArgsArgName | upgrade_shapes.rs:22:41:22:41 | 1 | 37 | 1 |
3+
| upgrade_shapes.rs:22:44:22:48 | FormatArgsArg | upgrade_shapes.rs:22:44:22:44 | FormatArgsArgName | upgrade_shapes.rs:22:48:22:48 | 2 | 44 | 2 |
4+
tryBlockModifierPreserved
5+
| upgrade_shapes.rs:21:13:21:21 | { ... } | upgrade_shapes.rs:21:13:21:21 | TryBlockModifier |
6+
structFieldDefaultPreserved
7+
| upgrade_shapes.rs:9:5:9:17 | field: u8 | upgrade_shapes.rs:9:17:9:17 | ConstArg | upgrade_shapes.rs:9:17:9:17 | 1 |
8+
variantDiscriminantPreserved
9+
| upgrade_shapes.rs:13:5:13:9 | V | upgrade_shapes.rs:13:9:13:9 | ConstArg | upgrade_shapes.rs:13:9:13:9 | 2 |
10+
pathMetaPreserved
11+
| upgrade_shapes.rs:4:3:4:11 | PathMeta | path_meta |
12+
| upgrade_shapes.rs:7:3:7:19 | PathMeta | path_meta |
13+
keyValueMetaPreserved
14+
| upgrade_shapes.rs:5:3:5:15 | KeyValueMeta | key_value | upgrade_shapes.rs:5:15:5:15 | 1 |
15+
tokenTreeMetaPreserved
16+
| upgrade_shapes.rs:6:3:6:18 | TokenTreeMeta | token_tree | upgrade_shapes.rs:6:13:6:18 | TokenTree |
17+
unsafeMetaPreserved
18+
| upgrade_shapes.rs:7:3:7:19 | UnsafeMeta | upgrade_shapes.rs:7:3:7:19 | PathMeta | path_meta |
19+
traitAliasPreserved
20+
| upgrade_shapes.rs:16:1:18:12 | trait Alias | upgrade_shapes.rs:16:7:16:11 | Alias | upgrade_shapes.rs:16:18:16:22 | ... | upgrade_shapes.rs:17:1:18:11 | WhereClause |
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import codeql.rust.elements
2+
3+
private predicate inUpgradeShapesFile(Locatable loc) {
4+
loc.getFile().getBaseName() = "upgrade_shapes.rs"
5+
}
6+
7+
query predicate formatArgNamePreserved(
8+
FormatArgsArg arg, FormatArgsArgName argName, Expr expr, int argNameColumn, string exprText
9+
) {
10+
inUpgradeShapesFile(arg) and
11+
argName = arg.getArgName() and
12+
expr = arg.getExpr() and
13+
argNameColumn = argName.getLocation().getStartColumn() and
14+
exprText = expr.toString()
15+
}
16+
17+
query predicate tryBlockModifierPreserved(BlockExpr block, TryBlockModifier modifier) {
18+
inUpgradeShapesFile(block) and
19+
modifier = block.getTryBlockModifier() and
20+
modifier.isTry() and
21+
not modifier.hasTypeRepr()
22+
}
23+
24+
query predicate structFieldDefaultPreserved(StructField field, ConstArg defaultVal, Expr expr) {
25+
inUpgradeShapesFile(field) and
26+
defaultVal = field.getDefaultVal() and
27+
expr = defaultVal.getExpr()
28+
}
29+
30+
query predicate variantDiscriminantPreserved(Variant variant, ConstArg constArg, Expr expr) {
31+
inUpgradeShapesFile(variant) and
32+
constArg = variant.getConstArg() and
33+
expr = constArg.getExpr()
34+
}
35+
36+
query predicate pathMetaPreserved(PathMeta meta, string pathText) {
37+
inUpgradeShapesFile(meta) and
38+
pathText = meta.getPath().getText() and
39+
pathText = "path_meta"
40+
}
41+
42+
query predicate keyValueMetaPreserved(KeyValueMeta meta, string pathText, Expr expr) {
43+
inUpgradeShapesFile(meta) and
44+
pathText = meta.getPath().getText() and
45+
pathText = "key_value" and
46+
expr = meta.getExpr()
47+
}
48+
49+
query predicate tokenTreeMetaPreserved(TokenTreeMeta meta, string pathText, TokenTree tokenTree) {
50+
inUpgradeShapesFile(meta) and
51+
pathText = meta.getPath().getText() and
52+
pathText = "token_tree" and
53+
tokenTree = meta.getTokenTree()
54+
}
55+
56+
query predicate unsafeMetaPreserved(UnsafeMeta meta, PathMeta inner, string pathText) {
57+
inUpgradeShapesFile(meta) and
58+
meta.isUnsafe() and
59+
inner = meta.getMeta() and
60+
pathText = inner.getPath().getText() and
61+
pathText = "path_meta"
62+
}
63+
64+
query predicate traitAliasPreserved(
65+
Trait trait, Name name, TypeBoundList bounds, WhereClause whereClause
66+
) {
67+
inUpgradeShapesFile(trait) and
68+
name = trait.getName() and
69+
name.getText() = "Alias" and
70+
bounds = trait.getTypeBoundList() and
71+
whereClause = trait.getWhereClause() and
72+
not trait.hasAssocItemList()
73+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
name: codeql/rust-upgrade-66a489863649185f4a9770f894505803059a1312-test-new
2+
version: 0.0.0
3+
dependencies:
4+
codeql/rust-all: ${workspace}
5+
extractor: rust
6+
tests: .
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#![allow(dead_code)]
2+
#![feature(more_qualified_paths)]
3+
4+
#[path_meta]
5+
#[key_value = 1]
6+
#[token_tree(list)]
7+
#[unsafe(path_meta)]
8+
struct S {
9+
field: u8 = 1,
10+
}
11+
12+
enum E {
13+
V = 2,
14+
}
15+
16+
trait Alias<T> = Clone
17+
where
18+
T: Copy;
19+
20+
fn f() {
21+
let _ = try { 1 };
22+
let _ = format_args!("{b} {a}", a = 1, b = 2);
23+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
formatArgsArgName
2+
| upgrade_shapes.rs:22:31:22:31 | a | upgrade_shapes.rs:22:35:22:35 | 1 | a |
3+
| upgrade_shapes.rs:22:38:22:38 | b | upgrade_shapes.rs:22:42:22:42 | 2 | b |
4+
metaExpr
5+
| upgrade_shapes.rs:5:1:5:15 | #[key_value = 1] | upgrade_shapes.rs:5:15:5:15 | 1 |
6+
metaIsUnsafe
7+
| upgrade_shapes.rs:7:1:7:21 | #[unsafe(path_meta)] |
8+
metaPath
9+
| upgrade_shapes.rs:4:1:4:12 | #[path_meta] | path_meta |
10+
| upgrade_shapes.rs:5:1:5:15 | #[key_value = 1] | key_value |
11+
| upgrade_shapes.rs:6:1:6:19 | #[token_tree(list)] | token_tree |
12+
| upgrade_shapes.rs:7:1:7:21 | #[unsafe(path_meta)] | path_meta |
13+
metaTokenTree
14+
| upgrade_shapes.rs:6:1:6:19 | #[token_tree(list)] | upgrade_shapes.rs:6:13:6:18 | (list) |
15+
structFieldDefault
16+
| upgrade_shapes.rs:9:5:9:17 | field: u8 = 1 | upgrade_shapes.rs:9:17:9:17 | 1 |
17+
traitAlias
18+
| upgrade_shapes.rs:16:1:18:12 | TraitAlias | Alias | upgrade_shapes.rs:16:18:16:23 | = Clone | upgrade_shapes.rs:17:1:18:12 | where... |
19+
tryBlock
20+
| upgrade_shapes.rs:21:13:21:23 | try { 1 } |
21+
variantDiscriminant
22+
| upgrade_shapes.rs:13:5:13:9 | V = 2 | upgrade_shapes.rs:13:9:13:9 | 2 |
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import codeql.rust.elements
2+
3+
private predicate inUpgradeShapesFile(Locatable loc) {
4+
loc.getFile().getBaseName() = "upgrade_shapes.rs"
5+
}
6+
7+
query predicate formatArgsArgName(FormatArgsArg arg, Name argName, Expr expr, string nameText) {
8+
inUpgradeShapesFile(arg) and
9+
argName = arg.getName() and
10+
expr = arg.getExpr() and
11+
nameText = argName.getText()
12+
}
13+
14+
query predicate tryBlock(BlockExpr block) {
15+
inUpgradeShapesFile(block) and
16+
block.isTry()
17+
}
18+
19+
query predicate structFieldDefault(StructField field, Expr defaultVal) {
20+
inUpgradeShapesFile(field) and
21+
defaultVal = field.getDefault()
22+
}
23+
24+
query predicate variantDiscriminant(Variant variant, Expr discriminant) {
25+
inUpgradeShapesFile(variant) and
26+
discriminant = variant.getDiscriminant()
27+
}
28+
29+
query predicate metaPath(Meta meta, string pathText) {
30+
inUpgradeShapesFile(meta) and
31+
pathText = meta.getPath().getText()
32+
}
33+
34+
query predicate metaExpr(Meta meta, Expr expr) {
35+
inUpgradeShapesFile(meta) and
36+
expr = meta.getExpr()
37+
}
38+
39+
query predicate metaTokenTree(Meta meta, TokenTree tokenTree) {
40+
inUpgradeShapesFile(meta) and
41+
tokenTree = meta.getTokenTree()
42+
}
43+
44+
query predicate metaIsUnsafe(Meta meta) {
45+
inUpgradeShapesFile(meta) and
46+
meta.isUnsafe()
47+
}
48+
49+
query predicate traitAlias(
50+
TraitAlias alias, Name name, TypeBoundList bounds, WhereClause whereClause
51+
) {
52+
inUpgradeShapesFile(alias) and
53+
name = alias.getName() and
54+
bounds = alias.getTypeBoundList() and
55+
whereClause = alias.getWhereClause()
56+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/usr/bin/env bash
2+
# Manual regression test for the Rust dbscheme upgrade from rust-analyzer 0.0.301 to 0.0.328.
3+
# See README.md for details.
4+
5+
set -euo pipefail
6+
7+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8+
REPO_ROOT="$(cd "$SCRIPT_DIR/../../../../.." && pwd)"
9+
OLD_COMMIT="${OLD_COMMIT:-491c373e076}" # origin/main at time of this upgrade
10+
11+
cd "$REPO_ROOT"
12+
13+
echo "==> Setting up temp directory for old test..."
14+
OLD_TEST_TMP=$(mktemp -d)
15+
trap 'rm -rf "$OLD_TEST_TMP"' EXIT
16+
17+
# Copy old test query and new test sources (qlpack, upgrade_shapes.rs) to temp
18+
cp "$SCRIPT_DIR/old/OldShapes.ql" "$SCRIPT_DIR/old/OldShapes.expected" "$OLD_TEST_TMP/"
19+
cp "$SCRIPT_DIR/new/qlpack.yml" "$SCRIPT_DIR/new/upgrade_shapes.rs" "$OLD_TEST_TMP/"
20+
21+
echo "==> Stashing any uncommitted changes..."
22+
git stash --quiet || true
23+
24+
restore_branch() {
25+
echo "==> Restoring original branch..."
26+
git checkout --quiet -
27+
git stash pop --quiet 2>/dev/null || true
28+
}
29+
trap 'restore_branch; rm -rf "$OLD_TEST_TMP"' EXIT
30+
31+
echo "==> Checking out old commit ($OLD_COMMIT)..."
32+
git checkout --quiet "$OLD_COMMIT"
33+
34+
echo "==> Building old extractor (this may take a while)..."
35+
bazel run //rust:install
36+
37+
echo "==> Creating old-schema test database..."
38+
rm -rf "$OLD_TEST_TMP"/*.testproj
39+
codeql test run \
40+
--search-path . \
41+
--keep-databases \
42+
"$OLD_TEST_TMP/OldShapes.ql"
43+
44+
echo "==> Copying dataset for upgrade..."
45+
cp -a "$OLD_TEST_TMP/test.testproj/db-rust" "$OLD_TEST_TMP/upgraded-dataset"
46+
47+
restore_branch
48+
trap 'rm -rf "$OLD_TEST_TMP"' EXIT
49+
50+
echo "==> Upgrading dataset to new schema..."
51+
codeql dataset upgrade "$OLD_TEST_TMP/upgraded-dataset" \
52+
--search-path . \
53+
--target-dbscheme rust/ql/lib/rust.dbscheme
54+
55+
echo "==> Running preservation test on upgraded dataset..."
56+
codeql test run \
57+
--search-path . \
58+
--dataset="$OLD_TEST_TMP/upgraded-dataset" \
59+
--check-databases \
60+
"$SCRIPT_DIR/new/UpgradeShapes.ql"
61+
62+
echo "==> All tests passed!"

0 commit comments

Comments
 (0)