Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add tests for file table engine #1353

Merged
merged 2 commits into from
Apr 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

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

5 changes: 5 additions & 0 deletions src/file-table-engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ license.workspace = true

[features]
default = []
test = ["common-test-util"]

[dependencies]
async-trait = "0.1"
Expand All @@ -14,6 +15,7 @@ common-error = { path = "../common/error" }
common-procedure = { path = "../common/procedure" }
common-query = { path = "../common/query" }
common-telemetry = { path = "../common/telemetry" }
common-time = { path = "../common/time" }
datatypes = { path = "../datatypes" }
futures.workspace = true
object-store = { path = "../object-store" }
Expand All @@ -25,3 +27,6 @@ store-api = { path = "../store-api" }
table = { path = "../table" }
common-test-util = { path = "../common/test-util", optional = true }
tokio.workspace = true

[dev-dependencies]
common-test-util = { path = "../common/test-util" }
16 changes: 16 additions & 0 deletions src/file-table-engine/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2023 Greptime 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.

#[derive(Debug, Clone, Default)]
pub struct EngineConfig {}
5 changes: 4 additions & 1 deletion src/file-table-engine/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.

pub mod immutable;
#[cfg(test)]
mod tests;
WenyXu marked this conversation as resolved.
Show resolved Hide resolved

use table::metadata::TableVersion;

pub mod immutable;
const INIT_TABLE_VERSION: TableVersion = 0;
51 changes: 48 additions & 3 deletions src/file-table-engine/src/engine/immutable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use table::requests::{AlterTableRequest, CreateTableRequest, DropTableRequest, O
use table::{error as table_error, Result as TableResult, Table, TableRef};
use tokio::sync::Mutex;

use crate::config::EngineConfig;
use crate::engine::INIT_TABLE_VERSION;
use crate::error::{
BuildTableInfoSnafu, BuildTableMetaSnafu, DropTableSnafu, InvalidRawSchemaSnafu, Result,
Expand Down Expand Up @@ -114,6 +115,21 @@ impl TableEngine for ImmutableFileTableEngine {
}
}

#[cfg(test)]
impl ImmutableFileTableEngine {
pub async fn close_table(&self, table_ref: &TableReference<'_>) -> TableResult<()> {
self.inner.close_table(table_ref).await
}
}

impl ImmutableFileTableEngine {
pub fn new(config: EngineConfig, object_store: ObjectStore) -> Self {
ImmutableFileTableEngine {
inner: Arc::new(EngineInner::new(config, object_store)),
}
}
}

struct EngineInner {
/// All tables opened by the engine. Map key is formatted [TableReference].
///
Expand All @@ -127,6 +143,14 @@ struct EngineInner {
}

impl EngineInner {
pub fn new(_config: EngineConfig, object_store: ObjectStore) -> Self {
EngineInner {
tables: RwLock::new(HashMap::default()),
object_store,
table_mutex: Mutex::new(()),
}
}

async fn create_table(
&self,
_ctx: &EngineContext,
Expand Down Expand Up @@ -309,7 +333,7 @@ impl EngineInner {
delete_table_manifest(
&table_full_name,
&table_manifest_dir(&table_dir),
self.object_store.clone(),
&self.object_store,
)
.await
.map_err(BoxedError::new)
Expand All @@ -327,15 +351,15 @@ impl EngineInner {
async fn close(&self) -> TableResult<()> {
let _lock = self.table_mutex.lock().await;

let mut tables = self.tables.write().unwrap().clone();
let tables = self.tables.read().unwrap().clone();

futures::future::try_join_all(tables.values().map(|t| t.close()))
.await
.map_err(BoxedError::new)
.context(table_error::TableOperationSnafu)?;

// Releases all closed table
tables.clear();
self.tables.write().unwrap().clear();

Ok(())
}
Expand All @@ -353,3 +377,24 @@ impl EngineInner {
.await
}
}

#[cfg(test)]
impl EngineInner {
pub async fn close_table(&self, table_ref: &TableReference<'_>) -> TableResult<()> {
let full_name = table_ref.to_string();

let _lock = self.table_mutex.lock().await;

if let Some(table) = self.get_table_by_full_name(&full_name) {
table
.close()
.await
.map_err(BoxedError::new)
.context(table_error::TableOperationSnafu)?;
}

self.tables.write().unwrap().remove(&full_name);

Ok(())
}
}
189 changes: 189 additions & 0 deletions src/file-table-engine/src/engine/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// Copyright 2023 Greptime 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.

use std::assert_matches::assert_matches;

use common_catalog::consts::{DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME, IMMUTABLE_FILE_ENGINE};
use table::engine::{EngineContext, TableEngine, TableReference};
use table::requests::{AlterKind, AlterTableRequest, DropTableRequest, OpenTableRequest};
use table::{error as table_error, Table};

use crate::manifest::immutable::manifest_path;
use crate::table::immutable::ImmutableFileTable;
use crate::test_util::{self, TestEngineComponents, TEST_TABLE_NAME};

#[tokio::test]
async fn test_get_table() {
let TestEngineComponents {
table_engine,
table_ref: table,
dir: _dir,
..
} = test_util::setup_test_engine_and_table("test_get_table").await;
let table_info = table.table_info();
let table_ref = TableReference {
catalog: &table_info.catalog_name,
schema: &table_info.schema_name,
table: &table_info.name,
};

let got = table_engine
.get_table(&EngineContext::default(), &table_ref)
.unwrap()
.unwrap();

assert_eq!(table.schema(), got.schema());
}

#[tokio::test]
async fn test_open_table() {
WenyXu marked this conversation as resolved.
Show resolved Hide resolved
common_telemetry::init_default_ut_logging();
let ctx = EngineContext::default();
let open_req = OpenTableRequest {
catalog_name: DEFAULT_CATALOG_NAME.to_string(),
schema_name: DEFAULT_SCHEMA_NAME.to_string(),
table_name: test_util::TEST_TABLE_NAME.to_string(),
// the test table id is 1
table_id: 1,
};

let table_ref = TableReference {
catalog: DEFAULT_CATALOG_NAME,
schema: DEFAULT_SCHEMA_NAME,
table: test_util::TEST_TABLE_NAME,
};

let TestEngineComponents {
table_engine,
table_ref: table,
dir: _dir,
..
} = test_util::setup_test_engine_and_table("test_open_table").await;

assert_eq!(IMMUTABLE_FILE_ENGINE, table_engine.name());

table_engine.close_table(&table_ref).await.unwrap();

let reopened = table_engine
.open_table(&ctx, open_req.clone())
.await
.unwrap()
.unwrap();

let reopened = reopened
.as_any()
.downcast_ref::<ImmutableFileTable>()
.unwrap();

let left = table.table_info();
let right = reopened.table_info();

// assert recovered table_info is correct
assert_eq!(left, right);
}

#[tokio::test]
async fn test_close_all_table() {
common_telemetry::init_default_ut_logging();

let table_ref = TableReference {
catalog: DEFAULT_CATALOG_NAME,
schema: DEFAULT_SCHEMA_NAME,
table: test_util::TEST_TABLE_NAME,
};

let TestEngineComponents {
table_engine,
dir: _dir,
..
} = test_util::setup_test_engine_and_table("test_close_all_table").await;

table_engine.close().await.unwrap();

let exist = table_engine.table_exists(&EngineContext::default(), &table_ref);

assert!(!exist);
}

#[tokio::test]
async fn test_alter_table() {
common_telemetry::init_default_ut_logging();
let TestEngineComponents {
table_engine,
dir: _dir,
..
} = test_util::setup_test_engine_and_table("test_alter_table").await;

let alter_req = AlterTableRequest {
catalog_name: DEFAULT_CATALOG_NAME.to_string(),
schema_name: DEFAULT_SCHEMA_NAME.to_string(),
table_name: TEST_TABLE_NAME.to_string(),
alter_kind: AlterKind::RenameTable {
new_table_name: "foo".to_string(),
},
};

let unsupported = table_engine
.alter_table(&EngineContext::default(), alter_req)
.await
.err()
.unwrap();

assert_matches!(unsupported, table_error::Error::Unsupported { .. })
}

#[tokio::test]
async fn test_drop_table() {
common_telemetry::init_default_ut_logging();

let drop_req = DropTableRequest {
catalog_name: DEFAULT_CATALOG_NAME.to_string(),
schema_name: DEFAULT_SCHEMA_NAME.to_string(),
table_name: TEST_TABLE_NAME.to_string(),
};

let TestEngineComponents {
table_engine,
object_store,
dir: _dir,
table_dir,
table_ref: table,
..
} = test_util::setup_test_engine_and_table("test_drop_table").await;

let table_info = table.table_info();
let table_ref = TableReference {
catalog: &table_info.catalog_name,
schema: &table_info.schema_name,
table: &table_info.name,
};

let dropped = table_engine
.drop_table(&EngineContext::default(), drop_req)
.await
.unwrap();

assert!(dropped);

let exist = table_engine.table_exists(&EngineContext::default(), &table_ref);
assert!(!exist);

// check table_dir manifest
let exist = object_store
.is_exist(&manifest_path(&table_dir))
.await
.unwrap();

assert!(!exist);
}
5 changes: 5 additions & 0 deletions src/file-table-engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(assert_matches)]

pub mod config;
pub mod engine;
pub mod error;
pub mod manifest;
pub mod table;
#[cfg(any(test, feature = "test"))]
pub(crate) mod test_util;
Loading