Skip to content

Commit 2aa1490

Browse files
authored
[sqllogictest] Read subdirectories in test_files (#5033)
* [sqllogictest] Read subdirectories in `test_files` * Update the relative path type * expect instead of unwrap * Keep only ascii characters in Postgres schema name * clippy
1 parent b5d90b6 commit 2aa1490

File tree

7 files changed

+90
-56
lines changed

7 files changed

+90
-56
lines changed

datafusion/core/tests/sqllogictests/src/engines/datafusion/mod.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18+
use std::path::PathBuf;
1819
use std::time::Duration;
1920

2021
use sqllogictest::DBOutput;
@@ -36,12 +37,12 @@ mod util;
3637

3738
pub struct DataFusion {
3839
ctx: SessionContext,
39-
file_name: String,
40+
relative_path: PathBuf,
4041
}
4142

4243
impl DataFusion {
43-
pub fn new(ctx: SessionContext, file_name: String) -> Self {
44-
Self { ctx, file_name }
44+
pub fn new(ctx: SessionContext, relative_path: PathBuf) -> Self {
45+
Self { ctx, relative_path }
4546
}
4647
}
4748

@@ -50,7 +51,11 @@ impl sqllogictest::AsyncDB for DataFusion {
5051
type Error = DFSqlLogicTestError;
5152

5253
async fn run(&mut self, sql: &str) -> Result<DBOutput> {
53-
println!("[{}] Running query: \"{}\"", self.file_name, sql);
54+
println!(
55+
"[{}] Running query: \"{}\"",
56+
self.relative_path.display(),
57+
sql
58+
);
5459
let result = run_query(&self.ctx, sql).await?;
5560
Ok(result)
5661
}

datafusion/core/tests/sqllogictests/src/engines/postgres/mod.rs

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18+
use std::path::{Path, PathBuf};
1819
use std::str::FromStr;
1920

2021
use async_trait::async_trait;
@@ -47,13 +48,13 @@ pub type Result<T, E = Error> = std::result::Result<T, E>;
4748
pub struct Postgres {
4849
client: tokio_postgres::Client,
4950
join_handle: JoinHandle<()>,
50-
/// Filename, for display purposes
51-
file_name: String,
51+
/// Relative test file path
52+
relative_path: PathBuf,
5253
}
5354

5455
impl Postgres {
55-
/// Creates a runner for executing queries against an existing
56-
/// posgres connection. `file_name` is used for display output
56+
/// Creates a runner for executing queries against an existing postgres connection.
57+
/// `relative_path` is used for display output and to create a postgres schema.
5758
///
5859
/// The database connection details can be overridden by the
5960
/// `PG_URI` environment variable.
@@ -65,9 +66,7 @@ impl Postgres {
6566
/// ```
6667
///
6768
/// See https://docs.rs/tokio-postgres/latest/tokio_postgres/config/struct.Config.html#url for format
68-
pub async fn connect(file_name: impl Into<String>) -> Result<Self> {
69-
let file_name = file_name.into();
70-
69+
pub async fn connect(relative_path: PathBuf) -> Result<Self> {
7170
let uri =
7271
std::env::var("PG_URI").map_or(PG_URI.to_string(), std::convert::identity);
7372

@@ -89,7 +88,7 @@ impl Postgres {
8988
}
9089
});
9190

92-
let schema = schema_name(&file_name);
91+
let schema = schema_name(&relative_path);
9392

9493
// create a new clean schema for running the test
9594
debug!("Creating new empty schema '{schema}'");
@@ -108,7 +107,7 @@ impl Postgres {
108107
Ok(Self {
109108
client,
110109
join_handle,
111-
file_name,
110+
relative_path,
112111
})
113112
}
114113

@@ -188,12 +187,18 @@ fn no_quotes(t: &str) -> &str {
188187

189188
/// Given a file name like pg_compat_foo.slt
190189
/// return a schema name
191-
fn schema_name(file_name: &str) -> &str {
192-
file_name
193-
.split('.')
194-
.next()
195-
.unwrap_or("default_schema")
196-
.trim_start_matches("pg_")
190+
fn schema_name(relative_path: &Path) -> String {
191+
relative_path
192+
.file_name()
193+
.map(|name| {
194+
name.to_string_lossy()
195+
.chars()
196+
.filter(|ch| ch.is_ascii_alphabetic())
197+
.collect::<String>()
198+
.trim_start_matches("pg_")
199+
.to_string()
200+
})
201+
.unwrap_or_else(|| "default_schema".to_string())
197202
}
198203

199204
impl Drop for Postgres {
@@ -249,7 +254,11 @@ impl sqllogictest::AsyncDB for Postgres {
249254
type Error = Error;
250255

251256
async fn run(&mut self, sql: &str) -> Result<DBOutput, Self::Error> {
252-
println!("[{}] Running query: \"{}\"", self.file_name, sql);
257+
println!(
258+
"[{}] Running query: \"{}\"",
259+
self.relative_path.display(),
260+
sql
261+
);
253262

254263
let lower_sql = sql.trim_start().to_ascii_lowercase();
255264

datafusion/core/tests/sqllogictests/src/main.rs

Lines changed: 56 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ mod engines;
2929
mod setup;
3030
mod utils;
3131

32-
const TEST_DIRECTORY: &str = "tests/sqllogictests/test_files";
32+
const TEST_DIRECTORY: &str = "tests/sqllogictests/test_files/";
3333
const PG_COMPAT_FILE_PREFIX: &str = "pg_compat_";
3434

3535
#[tokio::main]
@@ -47,40 +47,37 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
4747

4848
let options = Options::new();
4949

50-
let files: Vec<_> = read_test_files(&options);
51-
52-
info!("Running test files {:?}", files);
53-
54-
for path in files {
55-
let file_name = path.file_name().unwrap().to_str().unwrap().to_string();
56-
50+
for (path, relative_path) in read_test_files(&options) {
5751
if options.complete_mode {
58-
run_complete_file(&path, file_name).await?;
52+
run_complete_file(&path, relative_path).await?;
5953
} else if options.postgres_runner {
60-
run_test_file_with_postgres(&path, file_name).await?;
54+
run_test_file_with_postgres(&path, relative_path).await?;
6155
} else {
62-
run_test_file(&path, file_name).await?;
56+
run_test_file(&path, relative_path).await?;
6357
}
6458
}
6559

6660
Ok(())
6761
}
6862

69-
async fn run_test_file(path: &PathBuf, file_name: String) -> Result<(), Box<dyn Error>> {
70-
println!("Running with DataFusion runner: {}", path.display());
71-
let ctx = context_for_test_file(&file_name).await;
72-
let mut runner = sqllogictest::Runner::new(DataFusion::new(ctx, file_name));
63+
async fn run_test_file(
64+
path: &Path,
65+
relative_path: PathBuf,
66+
) -> Result<(), Box<dyn Error>> {
67+
info!("Running with DataFusion runner: {}", path.display());
68+
let ctx = context_for_test_file(&relative_path).await;
69+
let mut runner = sqllogictest::Runner::new(DataFusion::new(ctx, relative_path));
7370
runner.run_file_async(path).await?;
7471
Ok(())
7572
}
7673

7774
async fn run_test_file_with_postgres(
78-
path: &PathBuf,
79-
file_name: String,
75+
path: &Path,
76+
relative_path: PathBuf,
8077
) -> Result<(), Box<dyn Error>> {
8178
info!("Running with Postgres runner: {}", path.display());
8279

83-
let postgres_client = Postgres::connect(file_name).await?;
80+
let postgres_client = Postgres::connect(relative_path).await?;
8481

8582
sqllogictest::Runner::new(postgres_client)
8683
.run_file_async(path)
@@ -90,17 +87,15 @@ async fn run_test_file_with_postgres(
9087
}
9188

9289
async fn run_complete_file(
93-
path: &PathBuf,
94-
file_name: String,
90+
path: &Path,
91+
relative_path: PathBuf,
9592
) -> Result<(), Box<dyn Error>> {
9693
use sqllogictest::{default_validator, update_test_file};
9794

9895
info!("Using complete mode to complete: {}", path.display());
9996

100-
let ctx = context_for_test_file(&file_name).await;
101-
let mut runner = sqllogictest::Runner::new(DataFusion::new(ctx, file_name));
102-
103-
info!("Using complete mode to complete {}", path.display());
97+
let ctx = context_for_test_file(&relative_path).await;
98+
let mut runner = sqllogictest::Runner::new(DataFusion::new(ctx, relative_path));
10499
let col_separator = " ";
105100
let validator = default_validator;
106101
update_test_file(path, &mut runner, col_separator, validator)
@@ -110,18 +105,42 @@ async fn run_complete_file(
110105
Ok(())
111106
}
112107

113-
fn read_test_files(options: &Options) -> Vec<PathBuf> {
114-
std::fs::read_dir(TEST_DIRECTORY)
115-
.unwrap()
116-
.map(|path| path.unwrap().path())
117-
.filter(|path| options.check_test_file(path.as_path()))
118-
.filter(|path| options.check_pg_compat_file(path.as_path()))
119-
.collect()
108+
fn read_test_files<'a>(
109+
options: &'a Options,
110+
) -> Box<dyn Iterator<Item = (PathBuf, PathBuf)> + 'a> {
111+
Box::new(
112+
read_dir_recursive(TEST_DIRECTORY)
113+
.map(|path| {
114+
(
115+
path.clone(),
116+
PathBuf::from(
117+
path.to_string_lossy().strip_prefix(TEST_DIRECTORY).unwrap(),
118+
),
119+
)
120+
})
121+
.filter(|(_, relative_path)| options.check_test_file(relative_path))
122+
.filter(|(path, _)| options.check_pg_compat_file(path.as_path())),
123+
)
124+
}
125+
126+
fn read_dir_recursive<P: AsRef<Path>>(path: P) -> Box<dyn Iterator<Item = PathBuf>> {
127+
Box::new(
128+
std::fs::read_dir(path)
129+
.expect("Readable directory")
130+
.map(|path| path.expect("Readable entry").path())
131+
.flat_map(|path| {
132+
if path.is_dir() {
133+
read_dir_recursive(path)
134+
} else {
135+
Box::new(std::iter::once(path))
136+
}
137+
}),
138+
)
120139
}
121140

122141
/// Create a SessionContext, configured for the specific test
123-
async fn context_for_test_file(file_name: &str) -> SessionContext {
124-
match file_name {
142+
async fn context_for_test_file(relative_path: &Path) -> SessionContext {
143+
match relative_path.file_name().unwrap().to_str().unwrap() {
125144
"aggregate.slt" | "select.slt" => {
126145
info!("Registering aggregate tables");
127146
let ctx = SessionContext::new();
@@ -185,14 +204,15 @@ impl Options {
185204
/// To be compatible with this, treat the command line arguments as a
186205
/// filter and that does a substring match on each input. returns
187206
/// true f this path should be run
188-
fn check_test_file(&self, path: &Path) -> bool {
207+
fn check_test_file(&self, relative_path: &Path) -> bool {
189208
if self.filters.is_empty() {
190209
return true;
191210
}
192211

193212
// otherwise check if any filter matches
194-
let path_str = path.to_string_lossy();
195-
self.filters.iter().any(|filter| path_str.contains(filter))
213+
self.filters
214+
.iter()
215+
.any(|filter| relative_path.to_string_lossy().contains(filter))
196216
}
197217

198218
/// Postgres runner executes only tests in files with specific names

0 commit comments

Comments
 (0)