mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-18 18:46:17 +00:00
s3Select: add unit test case
Signed-off-by: junxiang Mu <1948535941@qq.com>
This commit is contained in:
@@ -21,6 +21,9 @@ pub mod object_store;
|
||||
pub mod query;
|
||||
pub mod server;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
pub type QueryResult<T> = Result<T, QueryError>;
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
@@ -90,3 +93,82 @@ impl Display for ResolvedTable {
|
||||
write!(f, "{table}")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use datafusion::common::DataFusionError;
|
||||
use datafusion::sql::sqlparser::parser::ParserError;
|
||||
|
||||
#[test]
|
||||
fn test_query_error_display() {
|
||||
let err = QueryError::NotImplemented {
|
||||
err: "feature X".to_string(),
|
||||
};
|
||||
assert_eq!(err.to_string(), "This feature is not implemented: feature X");
|
||||
|
||||
let err = QueryError::MultiStatement {
|
||||
num: 2,
|
||||
sql: "SELECT 1; SELECT 2;".to_string(),
|
||||
};
|
||||
assert_eq!(err.to_string(), "Multi-statement not allow, found num:2, sql:SELECT 1; SELECT 2;");
|
||||
|
||||
let err = QueryError::Cancel;
|
||||
assert_eq!(err.to_string(), "The query has been canceled");
|
||||
|
||||
let err = QueryError::FunctionNotExists {
|
||||
name: "my_func".to_string(),
|
||||
};
|
||||
assert_eq!(err.to_string(), "Udf not exists, name:my_func.");
|
||||
|
||||
let err = QueryError::StoreError {
|
||||
e: "connection failed".to_string(),
|
||||
};
|
||||
assert_eq!(err.to_string(), "Store Error, e:connection failed.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_error_from_datafusion_error() {
|
||||
let df_error = DataFusionError::Plan("invalid plan".to_string());
|
||||
let query_error: QueryError = df_error.into();
|
||||
|
||||
match query_error {
|
||||
QueryError::Datafusion { source, .. } => {
|
||||
assert!(source.to_string().contains("invalid plan"));
|
||||
}
|
||||
_ => panic!("Expected Datafusion error"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_error_from_parser_error() {
|
||||
let parser_error = ParserError::ParserError("syntax error".to_string());
|
||||
let query_error = QueryError::Parser { source: parser_error };
|
||||
|
||||
assert!(query_error.to_string().contains("syntax error"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolved_table() {
|
||||
let table = ResolvedTable {
|
||||
table: "my_table".to_string(),
|
||||
};
|
||||
|
||||
assert_eq!(table.table(), "my_table");
|
||||
assert_eq!(table.to_string(), "my_table");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolved_table_clone_and_eq() {
|
||||
let table1 = ResolvedTable {
|
||||
table: "table1".to_string(),
|
||||
};
|
||||
let table2 = table1.clone();
|
||||
let table3 = ResolvedTable {
|
||||
table: "table2".to_string(),
|
||||
};
|
||||
|
||||
assert_eq!(table1, table2);
|
||||
assert_ne!(table1, table3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2024 RustFS Team
|
||||
//
|
||||
// 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.
|
||||
|
||||
//! Test modules for s3select-api
|
||||
|
||||
pub mod query_execution_test;
|
||||
@@ -0,0 +1,167 @@
|
||||
// Copyright 2024 RustFS Team
|
||||
//
|
||||
// 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.
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::query::execution::{DONE, Output, QueryExecution, QueryState, QueryType, RUNNING};
|
||||
use crate::{QueryError, QueryResult};
|
||||
use async_trait::async_trait;
|
||||
|
||||
#[test]
|
||||
fn test_query_type_display() {
|
||||
assert_eq!(format!("{}", QueryType::Batch), "batch");
|
||||
assert_eq!(format!("{}", QueryType::Stream), "stream");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_type_equality() {
|
||||
assert_eq!(QueryType::Batch, QueryType::Batch);
|
||||
assert_ne!(QueryType::Batch, QueryType::Stream);
|
||||
assert_eq!(QueryType::Stream, QueryType::Stream);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_output_nil_methods() {
|
||||
let output = Output::Nil(());
|
||||
|
||||
let result = output.chunk_result().await;
|
||||
assert!(result.is_ok(), "Output::Nil result should be Ok");
|
||||
|
||||
let output2 = Output::Nil(());
|
||||
let rows = output2.num_rows().await;
|
||||
assert_eq!(rows, 0, "Output::Nil should have 0 rows");
|
||||
|
||||
let output3 = Output::Nil(());
|
||||
let affected = output3.affected_rows().await;
|
||||
assert_eq!(affected, 0, "Output::Nil should have 0 affected rows");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_state_as_ref() {
|
||||
let accepting = QueryState::ACCEPTING;
|
||||
assert_eq!(accepting.as_ref(), "ACCEPTING");
|
||||
|
||||
let running = QueryState::RUNNING(RUNNING::ANALYZING);
|
||||
assert_eq!(running.as_ref(), "ANALYZING");
|
||||
|
||||
let done = QueryState::DONE(DONE::FINISHED);
|
||||
assert_eq!(done.as_ref(), "FINISHED");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_running_state_as_ref() {
|
||||
assert_eq!(RUNNING::DISPATCHING.as_ref(), "DISPATCHING");
|
||||
assert_eq!(RUNNING::ANALYZING.as_ref(), "ANALYZING");
|
||||
assert_eq!(RUNNING::OPTMIZING.as_ref(), "OPTMIZING");
|
||||
assert_eq!(RUNNING::SCHEDULING.as_ref(), "SCHEDULING");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_done_state_as_ref() {
|
||||
assert_eq!(DONE::FINISHED.as_ref(), "FINISHED");
|
||||
assert_eq!(DONE::FAILED.as_ref(), "FAILED");
|
||||
assert_eq!(DONE::CANCELLED.as_ref(), "CANCELLED");
|
||||
}
|
||||
|
||||
// Mock implementation for testing
|
||||
struct MockQueryExecution {
|
||||
should_succeed: bool,
|
||||
should_cancel: bool,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl QueryExecution for MockQueryExecution {
|
||||
async fn start(&self) -> QueryResult<Output> {
|
||||
if self.should_cancel {
|
||||
return Err(QueryError::Cancel);
|
||||
}
|
||||
|
||||
if self.should_succeed {
|
||||
Ok(Output::Nil(()))
|
||||
} else {
|
||||
Err(QueryError::NotImplemented {
|
||||
err: "Mock execution failed".to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn cancel(&self) -> QueryResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_mock_query_execution_success() {
|
||||
let execution = MockQueryExecution {
|
||||
should_succeed: true,
|
||||
should_cancel: false,
|
||||
};
|
||||
|
||||
let result = execution.start().await;
|
||||
assert!(result.is_ok(), "Mock execution should succeed");
|
||||
|
||||
if let Ok(Output::Nil(_)) = result {
|
||||
// Expected result
|
||||
} else {
|
||||
panic!("Expected Output::Nil");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_mock_query_execution_failure() {
|
||||
let execution = MockQueryExecution {
|
||||
should_succeed: false,
|
||||
should_cancel: false,
|
||||
};
|
||||
|
||||
let result = execution.start().await;
|
||||
assert!(result.is_err(), "Mock execution should fail");
|
||||
|
||||
if let Err(QueryError::NotImplemented { .. }) = result {
|
||||
// Expected error
|
||||
} else {
|
||||
panic!("Expected NotImplemented error");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_mock_query_execution_cancel() {
|
||||
let execution = MockQueryExecution {
|
||||
should_succeed: false,
|
||||
should_cancel: true,
|
||||
};
|
||||
|
||||
let result = execution.start().await;
|
||||
assert!(result.is_err(), "Cancelled execution should fail");
|
||||
|
||||
if let Err(QueryError::Cancel) = result {
|
||||
// Expected cancellation error
|
||||
} else {
|
||||
panic!("Expected Cancel error");
|
||||
}
|
||||
|
||||
let cancel_result = execution.cancel();
|
||||
assert!(cancel_result.is_ok(), "Cancel should succeed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_execution_default_type() {
|
||||
let execution = MockQueryExecution {
|
||||
should_succeed: true,
|
||||
should_cancel: false,
|
||||
};
|
||||
|
||||
assert_eq!(execution.query_type(), QueryType::Batch);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user