Skip to content

Commit 10d0c4a

Browse files
redsun82Copilot
andcommitted
Rust: Move upgrade test to separate upgrade-tests directory
Avoids issues with nested qlpack.yml breaking `codeql pack create` for the lib pack. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent e372e2d commit 10d0c4a

11 files changed

Lines changed: 308 additions & 0 deletions

File tree

codeql-workspace.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ provide:
22
- "*/ql/src/qlpack.yml"
33
- "*/ql/lib/qlpack.yml"
44
- "*/ql/test*/qlpack.yml"
5+
- "*/ql/upgrade-tests/qlpack.yml"
56
- "*/ql/examples/qlpack.yml"
67
- "*/ql/consistency-queries/qlpack.yml"
78
- "*/ql/automodel/src/qlpack.yml"

rust/ql/upgrade-tests/.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
target/
2+
3+
# these are all generated, see `rust/extractor/src/qltest.rs` for details
4+
Cargo.toml
5+
/*/**/rust-toolchain.toml
6+
lib.rs
7+
.proc_macro/
8+
.lib/
9+
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: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Upgrade Regression Test for rust-analyzer 0.0.301 → 0.0.328
2+
3+
This test verifies that the dbscheme upgrade script correctly preserves data when migrating databases from the old schema to the new schema.
4+
5+
## Running the test
6+
7+
```bash
8+
./run-test.sh
9+
```
10+
11+
This will:
12+
1. Stash any uncommitted changes
13+
2. Check out the old commit (491c373e076)
14+
3. Build the old extractor
15+
4. Create a database with the old schema from `upgrade_shapes.rs`
16+
5. Restore your branch
17+
6. Upgrade the database to the new schema
18+
7. Verify that the old properties are still accessible via the new schema
19+
20+
## Files
21+
22+
- `old.ql` / `old.expected`: Query for the old schema (validates extraction)
23+
- `new.ql` / `new.expected`: Query for the new schema (validates upgrade preserved data)
24+
- `upgrade_shapes.rs`: Rust source containing test shapes for all affected schema elements
25+
- `run-test.sh`: Test runner script
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: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
formatArgsArgName
2+
| upgrade_shapes.rs:22:37:22:41 | FormatArgsArg | upgrade_shapes.rs:22:37:22:37 | a | upgrade_shapes.rs:22:41:22:41 | 1 | a |
3+
| upgrade_shapes.rs:22:44:22:48 | FormatArgsArg | upgrade_shapes.rs:22:44:22:44 | b | upgrade_shapes.rs:22:48:22:48 | 2 | b |
4+
tryBlock
5+
| upgrade_shapes.rs:21:13:21:21 | { ... } |
6+
structFieldDefault
7+
| upgrade_shapes.rs:9:5:9:17 | field: u8 | upgrade_shapes.rs:9:17:9:17 | 1 |
8+
variantDiscriminant
9+
| upgrade_shapes.rs:13:5:13:9 | V | upgrade_shapes.rs:13:9:13:9 | 2 |
10+
metaPath
11+
| upgrade_shapes.rs:1:4:1:19 | Meta | allow |
12+
| upgrade_shapes.rs:2:4:2:32 | Meta | feature |
13+
| upgrade_shapes.rs:4:3:4:11 | Meta | path_meta |
14+
| upgrade_shapes.rs:5:3:5:15 | Meta | key_value |
15+
| upgrade_shapes.rs:6:3:6:18 | Meta | token_tree |
16+
| upgrade_shapes.rs:7:3:7:19 | Meta | path_meta |
17+
metaExpr
18+
| upgrade_shapes.rs:5:3:5:15 | Meta | upgrade_shapes.rs:5:15:5:15 | 1 |
19+
metaTokenTree
20+
| upgrade_shapes.rs:1:4:1:19 | Meta | upgrade_shapes.rs:1:9:1:19 | TokenTree |
21+
| upgrade_shapes.rs:2:4:2:32 | Meta | upgrade_shapes.rs:2:11:2:32 | TokenTree |
22+
| upgrade_shapes.rs:6:3:6:18 | Meta | upgrade_shapes.rs:6:13:6:18 | TokenTree |
23+
metaIsUnsafe
24+
| upgrade_shapes.rs:7:3:7:19 | Meta |
25+
traitAlias
26+
| upgrade_shapes.rs:16:1:18:12 | TraitAlias | 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: 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: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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="$(git rev-parse --show-toplevel)"
9+
OLD_COMMIT="${OLD_COMMIT:-491c373e076}" # origin/main at time of this upgrade
10+
11+
cd "$REPO_ROOT"
12+
13+
# Require clean working directory - stash handling is too fragile
14+
if ! git diff --quiet HEAD || [ -n "$(git ls-files --others --exclude-standard)" ]; then
15+
echo "ERROR: Working directory has uncommitted changes." >&2
16+
echo "Please commit or stash your changes before running this test." >&2
17+
exit 1
18+
fi
19+
20+
ORIGINAL_REF="$(git rev-parse --abbrev-ref HEAD)"
21+
if [ "$ORIGINAL_REF" = "HEAD" ]; then
22+
# Detached HEAD - save the commit instead
23+
ORIGINAL_REF="$(git rev-parse HEAD)"
24+
fi
25+
26+
restore_ref() {
27+
echo "==> Restoring original ref ($ORIGINAL_REF)..."
28+
git checkout --quiet "$ORIGINAL_REF"
29+
}
30+
trap 'restore_ref' EXIT
31+
32+
echo "==> Checking out old commit ($OLD_COMMIT)..."
33+
git checkout --quiet "$OLD_COMMIT"
34+
35+
# Restore the upgrade-tests directory from the original ref (it doesn't exist in old commit)
36+
git checkout --quiet "$ORIGINAL_REF" -- rust/ql/upgrade-tests codeql-workspace.yml
37+
38+
echo "==> Building old extractor (this may take a while)..."
39+
bazel run //rust:install
40+
41+
echo "==> Creating old-schema test database..."
42+
codeql test run \
43+
--search-path . \
44+
--keep-databases \
45+
"$SCRIPT_DIR/old.ql" "$@"
46+
47+
restore_ref
48+
trap '' EXIT
49+
50+
echo "==> Upgrading dataset to new schema..."
51+
DATASET_DIR=("$SCRIPT_DIR"/*.testproj/db-rust)
52+
if [[ ! -d "${DATASET_DIR[0]}" ]]; then
53+
echo "ERROR: No testproj found at $SCRIPT_DIR/*.testproj" >&2
54+
exit 1
55+
fi
56+
codeql dataset upgrade "${DATASET_DIR[0]}" \
57+
--search-path . \
58+
--target-dbscheme rust/ql/lib/rust.dbscheme
59+
60+
echo "==> Running preservation test on upgraded dataset..."
61+
codeql test run \
62+
--search-path . \
63+
--dataset "${DATASET_DIR[0]}" \
64+
--check-databases \
65+
"$SCRIPT_DIR/new.ql" "$@"
66+
67+
echo "==> All tests passed!"
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+
}

0 commit comments

Comments
 (0)