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