Skip to content

Commit

Permalink
chore(sqlparser): add do-apply-parser-test (#8486)
Browse files Browse the repository at this point in the history
Signed-off-by: TennyZhuang <zty0826@gmail.com>
  • Loading branch information
TennyZhuang authored Mar 11, 2023
1 parent a77f6cc commit 00ea62a
Show file tree
Hide file tree
Showing 19 changed files with 300 additions and 234 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ extend = [
{ path = "src/risedevtool/redis.toml" },
{ path = "src/risedevtool/connector.toml" },
{ path = "src/risedevtool/risedev-components.toml" },
{ path = "src/sqlparser/test_runner/sqlparser_test.toml"},
{ path = "src/frontend/planner_test/planner_test.toml" },
{ path = "src/tests/compaction_test/Makefile.toml" },
{ path = "src/storage/backup/integration_tests/Makefile.toml" },
Expand Down
2 changes: 1 addition & 1 deletion src/cmd_all/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ ignored = ["workspace-hack", "workspace-config", "task_stats_alloc"]
[dependencies]
anyhow = "1"
clap = { version = "4", features = ["derive"] }
console = "0.15.2"
console = "0.15"
risingwave_common = { path = "../common" }
risingwave_compactor = { path = "../storage/compactor" }
risingwave_compute = { path = "../compute" }
Expand Down
16 changes: 16 additions & 0 deletions src/sqlparser/test_runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,27 @@ normal = ["workspace-hack"]

[dependencies]
anyhow = "1"
console = "0.15"
futures = { version = "0.3", default-features = false, features = ["alloc"] }
risingwave_sqlparser = { path = "../" }
serde = { version = "1", features = ["derive"] }
serde_with = "2"
serde_yaml = "0.9"
tokio = { version = "0.2", package = "madsim-tokio", features = [
"rt",
"rt-multi-thread",
"sync",
"macros",
"time",
"signal",
"fs",
] }
walkdir = "2"

[[bin]]
name = "parser-test-apply"
path = "src/bin/apply.rs"

[target.'cfg(not(madsim))'.dependencies]
workspace-hack = { path = "../../workspace-hack" }

Expand Down
55 changes: 55 additions & 0 deletions src/sqlparser/test_runner/sqlparser_test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
[tasks.update-parser-test]
description = "Update parser test data"
private = true
script = '''
#!/usr/bin/env bash
set -e
cargo run --bin parser-test-apply
'''

[tasks.apply-parser-test]
description = "Generate parser test data"
dependencies = [
"update-parser-test"
]
script = '''
#!/usr/bin/env bash
set -e
cd src/sqlparser/tests/testdata/
for f in *.apply.yaml
do
diff "$f" "$(basename "$f" .apply.yaml).yaml" || true
done
echo "If you want to apply the parser test data, run: $(tput setaf 2)./risedev do-apply-parser-test$(tput sgr 0)"
'''
category = "RiseDev - Test"

[tasks.do-apply-parser-test]
description = "Apply parser test data"
dependencies = [
"update-parser-test"
]
script = '''
#!/usr/bin/env bash
set -e
cd src/sqlparser/tests/testdata/
for f in *.apply.yaml
do
SOURCE="$(basename $f .apply.yaml).yaml"
if [ -f "$SOURCE" ]; then
cat <<EOF > temp.apply.yaml
# This file is automatically generated. See \`src/sqlparser/test_runner/src/bin/apply.rs\` for more information.
EOF
cat "$f" >> temp.apply.yaml
mv temp.apply.yaml "$SOURCE"
fi
done
rm *.apply.yaml
echo "$(tput setaf 2)Diff applied!$(tput sgr 0)"
'''
category = "RiseDev - Test"
121 changes: 121 additions & 0 deletions src/sqlparser/test_runner/src/bin/apply.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright 2023 RisingWave Labs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::path::Path;
use std::sync::{Arc, Mutex};

use anyhow::Result;
use console::style;
use futures::future::try_join_all;
use risingwave_sqlparser::ast::Statement;
use risingwave_sqlparser::parser::Parser;
use risingwave_sqlparser_test_runner::TestCase;
use walkdir::WalkDir;

#[tokio::main]
async fn main() -> Result<()> {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let dir = Path::new(manifest_dir)
.parent()
.unwrap()
.join("tests")
.join("testdata");
println!("Using test cases from {:?}", dir);

let mut futs = vec![];

let log_lock = Arc::new(Mutex::new(()));

for entry in WalkDir::new(dir) {
let entry = entry.unwrap();
let path = entry.path();

if !path.is_file() {
continue;
}

if path.is_file()
&& path.extension().map_or(false, |p| {
p.eq_ignore_ascii_case("yml") || p.eq_ignore_ascii_case("yaml")
})
&& !path
.file_name()
.unwrap()
.to_string_lossy()
.ends_with(".apply.yaml")
{
let target = path.with_extension("apply.yaml");

let path = path.to_path_buf();
let log_lock = Arc::clone(&log_lock);
futs.push(async move {
let file_content = tokio::fs::read_to_string(&path).await?;

let cases: Vec<TestCase> = serde_yaml::from_str(&file_content)?;

let mut new_cases = Vec::with_capacity(cases.len());

for case in cases {
let input = &case.input;
let ast = Parser::parse_sql(input);
let actual_case = match ast {
Ok(ast) => {
let [ast]: [Statement; 1] = ast
.try_into()
.expect("Only one statement is supported now.");

let actual_formatted_sql =
case.formatted_sql.as_ref().map(|_| format!("{}", ast));
let actual_formatted_ast =
case.formatted_ast.as_ref().map(|_| format!("{:?}", ast));

TestCase {
input: input.clone(),
formatted_sql: actual_formatted_sql,
formatted_ast: actual_formatted_ast,
error_msg: None,
}
}
Err(err) => {
let actual_error_msg = format!("{}", err);
TestCase {
input: input.clone(),
formatted_sql: None,
formatted_ast: None,
error_msg: Some(actual_error_msg),
}
}
};

if actual_case != case {
let _guard = log_lock.lock();
println!("{}\n{}\n", style(&case).red(), style(&actual_case).green())
}

new_cases.push(actual_case);
}

let output_content = serde_yaml::to_string(&new_cases)?;

tokio::fs::write(target, output_content).await?;

Ok::<_, anyhow::Error>(())
});
}
}

let _res = try_join_all(futs).await?;

Ok(())
}
33 changes: 25 additions & 8 deletions src/sqlparser/test_runner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,27 @@

// Data-driven tests.

use std::fmt::Display;

use anyhow::{anyhow, Result};
use risingwave_sqlparser::parser::Parser;
use serde::Deserialize;
use serde::{Deserialize, Serialize};

/// `TestCase` will be deserialized from yaml.
#[derive(PartialEq, Eq, Debug, Deserialize)]
struct TestCase {
input: String,
formatted_sql: Option<String>,
error_msg: Option<String>,
formatted_ast: Option<String>,
#[serde_with::skip_serializing_none]
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TestCase {
pub input: String,
pub formatted_sql: Option<String>,
pub error_msg: Option<String>,
pub formatted_ast: Option<String>,
}

impl Display for TestCase {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&serde_yaml::to_string(self).unwrap())
}
}

fn run_test_case(c: TestCase) -> Result<()> {
Expand Down Expand Up @@ -97,7 +107,14 @@ pub fn run_all_test_files() {
use walkdir::WalkDir;
for entry in WalkDir::new("../tests/testdata/") {
let entry = entry.unwrap();
if !entry.path().is_file() {
if !(entry.path().is_file()) {
continue;
}
if !(entry
.path()
.extension()
.map_or(false, |p| p.eq_ignore_ascii_case("yaml")))
{
continue;
}
let file_content = std::fs::read_to_string(entry.path()).unwrap();
Expand Down
1 change: 1 addition & 0 deletions src/sqlparser/tests/testdata/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.apply.yaml
4 changes: 1 addition & 3 deletions src/sqlparser/tests/testdata/alter.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
# This file is automatically generated. See `src/sqlparser/test_runner/src/bin/apply.rs` for more information.
- input: ALTER USER user WITH SUPERUSER CREATEDB PASSWORD 'password'
formatted_sql: ALTER USER user WITH SUPERUSER CREATEDB PASSWORD 'password'

- input: ALTER USER user RENAME TO another
formatted_sql: ALTER USER user RENAME TO another

- input: ALTER SYSTEM SET a = 'abc'
formatted_sql: ALTER SYSTEM SET a = 'abc'

- input: ALTER SYSTEM SET a = DEFAULT
formatted_sql: ALTER SYSTEM SET a = DEFAULT
19 changes: 4 additions & 15 deletions src/sqlparser/tests/testdata/array.yaml
Original file line number Diff line number Diff line change
@@ -1,32 +1,21 @@
# This file is automatically generated. See `src/sqlparser/test_runner/src/bin/apply.rs` for more information.
- input: CREATE TABLE t(a int[]);
formatted_sql: CREATE TABLE t (a INT[])

- input: CREATE TABLE t(a int[][]);
formatted_sql: CREATE TABLE t (a INT[][])

- input: CREATE TABLE t(a int[][][]);
formatted_sql: CREATE TABLE t (a INT[][][])

- input: CREATE TABLE t(a int[);
error_msg: |
sql parser error: Expected ], found: )
error_msg: 'sql parser error: Expected ], found: )'
- input: CREATE TABLE t(a int[[]);
error_msg: |
sql parser error: Expected ], found: [
error_msg: 'sql parser error: Expected ], found: ['
- input: CREATE TABLE t(a int]);
error_msg: |
sql parser error: Expected ',' or ')' after column definition, found: ]
error_msg: 'sql parser error: Expected '','' or '')'' after column definition, found: ]'
- input: SELECT foo[0] FROM foos
formatted_sql: SELECT foo[0] FROM foos

- input: SELECT foo[0][0] FROM foos
formatted_sql: SELECT foo[0][0] FROM foos

- input: SELECT (CAST(ARRAY[ARRAY[2, 3]] AS INT[][]))[1][2]
formatted_sql: SELECT (CAST(ARRAY[ARRAY[2, 3]] AS INT[][]))[1][2]

- input: SELECT ARRAY[]
formatted_sql: SELECT ARRAY[]
Loading

0 comments on commit 00ea62a

Please sign in to comment.