From 719d8f23e1f537e9e0f66333004575c7513a69a3 Mon Sep 17 00:00:00 2001 From: Hayden Hung Hoang Date: Tue, 21 Oct 2025 23:50:37 +0700 Subject: [PATCH 1/5] feat: xtask to run test & clean up --- .cargo/config.toml | 3 ++- Cargo.toml | 3 +++ typesense/Cargo.toml | 2 +- xtask/Cargo.toml | 2 ++ xtask/src/main.rs | 17 ++++++++++++++ xtask/src/test_clean.rs | 49 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 xtask/src/test_clean.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index f0ccbc9..3b8bc0d 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,2 +1,3 @@ [alias] -xtask = "run --package xtask --" \ No newline at end of file +xtask = "run --package xtask --" +test-clean = "run --package xtask -- test-clean" diff --git a/Cargo.toml b/Cargo.toml index 36c1189..626ce20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,3 +33,6 @@ sha2 = "0.10" thiserror = "2" url = "2" web-time = "=1.1.0" +# dev dependencies +tokio = { version = "1.5", features = ["macros", "rt", "rt-multi-thread"] } + diff --git a/typesense/Cargo.toml b/typesense/Cargo.toml index b25914f..7c88c38 100644 --- a/typesense/Cargo.toml +++ b/typesense/Cargo.toml @@ -48,7 +48,7 @@ trybuild = "1.0.42" # native-only dev deps [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] -tokio = { version = "1.5", features = ["macros", "rt", "rt-multi-thread"] } +tokio = { workspace = true} wiremock = "0.6" # wasm test deps diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index f13f365..a37b55b 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -10,3 +10,5 @@ clap = { workspace = true } reqwest = { version = "0.12", features = ["blocking"] } # "blocking" is simpler for scripts serde = { workspace = true } serde_yaml = { workspace = true } +typesense = { path = "../typesense"} +tokio = { workspace = true} diff --git a/xtask/src/main.rs b/xtask/src/main.rs index b90865b..75c9f73 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -3,8 +3,11 @@ use clap::{Parser, ValueEnum}; use std::{env, fs, process::Command}; mod add_vendor_attributes; mod preprocess_openapi; +mod test_clean; mod vendor_attributes; + use preprocess_openapi::preprocess_openapi_file; +use test_clean::test_clean; const SPEC_URL: &str = "https://raw.githubusercontent.com/typesense/typesense-api-spec/master/openapi.yml"; @@ -27,6 +30,10 @@ struct Cli { /// The list of tasks to run in sequence. #[arg(required = true, value_enum)] tasks: Vec, + + /// Arguments to forward to cargo test + #[arg(last(true))] + test_args: Vec, } #[derive(ValueEnum, Clone, Debug)] @@ -38,11 +45,15 @@ enum Task { Fetch, /// Preprocesses fetched OpenAPI spec file into a new one Preprocess, + /// Clean up test artifacts, e.g., collections + TestClean, } fn main() -> Result<()> { let cli = Cli::parse(); + let rt = tokio::runtime::Runtime::new().unwrap(); + for task in cli.tasks { println!("▶️ Running task: {:?}", task); match task { @@ -50,6 +61,12 @@ fn main() -> Result<()> { Task::Fetch => task_fetch_api_spec()?, Task::Preprocess => preprocess_openapi_file(INPUT_SPEC_FILE, OUTPUT_PREPROCESSED_FILE) .expect("Preprocess failed, aborting!"), + Task::TestClean => { + let test_args = cli.test_args.clone(); + rt.block_on(async move { + test_clean(test_args).await; + }); + } } } Ok(()) diff --git a/xtask/src/test_clean.rs b/xtask/src/test_clean.rs new file mode 100644 index 0000000..6d7c2ab --- /dev/null +++ b/xtask/src/test_clean.rs @@ -0,0 +1,49 @@ +use std::time::Duration; +use typesense::{Client, ExponentialBackoff, models::GetCollectionsParameters}; + +async fn clean_test_artifacts() { + let client = Client::builder() + .nodes(vec!["http://localhost:8108"]) + .api_key("xyz") + .healthcheck_interval(Duration::from_secs(5)) + .retry_policy(ExponentialBackoff::builder().build_with_max_retries(3)) + .connection_timeout(Duration::from_secs(3)) + .build() + .expect("Failed to create Typesense client"); + + let collections = client + .collections() + .retrieve(GetCollectionsParameters::new()) + .await + .expect("Get all collections failed!"); + + println!("Cleaning up {} test collections...", collections.len()); + + for collection in collections.iter() { + if let Err(err) = client + .collection_schemaless(&collection.name) + .delete() + .await + { + eprintln!("Failed to delete {}: {}", collection.name, err); + } else { + println!("Deleted {}", collection.name); + } + } + println!("✅ Cleanup complete."); +} + +pub async fn test_clean(args: Vec) { + println!("Run test with arguments {}", args.join(" ")); + // Run `cargo test` with the forwarded arguments + let status = std::process::Command::new("cargo") + .arg("test") + .args(&args) + .status() + .expect("Failed to run cargo test"); + + clean_test_artifacts().await; + + // Propagate cargo test exit code + std::process::exit(status.code().unwrap_or(1)); +} From eaec219f28ad11ae7b19654d0f7e371187ab80de Mon Sep 17 00:00:00 2001 From: Hayden Hung Hoang Date: Wed, 22 Oct 2025 23:22:38 +0700 Subject: [PATCH 2/5] feat(xtask): aliased command to run wasm test --- README.md | 22 ++++++++++++++++++++++ xtask/src/main.rs | 7 ++++++- xtask/src/test_clean.rs | 27 +++++++++++++++++++-------- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index a07c726..75d1059 100644 --- a/README.md +++ b/README.md @@ -41,4 +41,26 @@ docker run --rm \ --additional-properties useSingleRequestParameter=true ``` +### Testing + +Make sure you have a Typesense server up and running: + +```bash +docker compose up +``` + +Then run this command in the root folder to run the integration tests: + +```bash +cargo test-clean -- --all-features +``` + +This is an aliased command which will run a script to clean up your Typesense server after the tests finish. You can pass any arguments of `cargo test` after the `--`. + +To run test for wasm: + +```bash +cargo test-clean --wasm +``` + If you'd like to contribute, please join our [Slack Community](https://join.slack.com/t/typesense-community/shared_invite/zt-mx4nbsbn-AuOL89O7iBtvkz136egSJg) and say hello! diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 75c9f73..29f84c9 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -31,6 +31,10 @@ struct Cli { #[arg(required = true, value_enum)] tasks: Vec, + /// Flag to run tests for wasm. + #[arg(long)] + wasm: bool, + /// Arguments to forward to cargo test #[arg(last(true))] test_args: Vec, @@ -63,8 +67,9 @@ fn main() -> Result<()> { .expect("Preprocess failed, aborting!"), Task::TestClean => { let test_args = cli.test_args.clone(); + let is_wasm = cli.wasm; rt.block_on(async move { - test_clean(test_args).await; + test_clean(is_wasm, test_args).await; }); } } diff --git a/xtask/src/test_clean.rs b/xtask/src/test_clean.rs index 6d7c2ab..57e09c3 100644 --- a/xtask/src/test_clean.rs +++ b/xtask/src/test_clean.rs @@ -33,14 +33,25 @@ async fn clean_test_artifacts() { println!("✅ Cleanup complete."); } -pub async fn test_clean(args: Vec) { - println!("Run test with arguments {}", args.join(" ")); - // Run `cargo test` with the forwarded arguments - let status = std::process::Command::new("cargo") - .arg("test") - .args(&args) - .status() - .expect("Failed to run cargo test"); +pub async fn test_clean(is_wasm: bool, args: Vec) { + let status = if is_wasm { + println!("Running wasm-pack test..."); + std::process::Command::new("wasm-pack") + .arg("test") + .arg("--headless") + .arg("--chrome") + .args(&args) + .arg("typesense") + .status() + .expect("Failed to run wasm-pack test") + } else { + println!("Running cargo test with arguments: {}", args.join(" ")); + std::process::Command::new("cargo") + .arg("test") + .args(&args) + .status() + .expect("Failed to run cargo test") + }; clean_test_artifacts().await; From 54c8f7b3aa862d8a6a2f099bb649126e29a5c659 Mon Sep 17 00:00:00 2001 From: Hayden Hung Hoang Date: Wed, 22 Oct 2025 23:24:11 +0700 Subject: [PATCH 3/5] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 75d1059..c513a50 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Then run this command in the root folder to run the integration tests: cargo test-clean -- --all-features ``` -This is an aliased command which will run a script to clean up your Typesense server after the tests finish. You can pass any arguments of `cargo test` after the `--`. +This is an alias command which will run a script to clean up your Typesense server after the tests finish. You can pass any arguments of `cargo test` after the `--`. To run test for wasm: From def2bb41a69a7286ce7c2cca5a7ecfaf1e6b8ff0 Mon Sep 17 00:00:00 2001 From: Hayden Hung Hoang Date: Wed, 22 Oct 2025 23:37:31 +0700 Subject: [PATCH 4/5] readme: wasm test clarity --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c513a50..a9fc390 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ cargo test-clean -- --all-features This is an alias command which will run a script to clean up your Typesense server after the tests finish. You can pass any arguments of `cargo test` after the `--`. -To run test for wasm: +To run test for wasm (chrome, headless): ```bash cargo test-clean --wasm From 93e75260b6a4248fe2488ae03ee0d01a79ae385f Mon Sep 17 00:00:00 2001 From: Hayden Hung Hoang Date: Thu, 23 Oct 2025 18:23:46 +0700 Subject: [PATCH 5/5] xtask: test clean up only delete collection with `test_` prefix --- xtask/src/test_clean.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/xtask/src/test_clean.rs b/xtask/src/test_clean.rs index 57e09c3..9acabf1 100644 --- a/xtask/src/test_clean.rs +++ b/xtask/src/test_clean.rs @@ -17,9 +17,15 @@ async fn clean_test_artifacts() { .await .expect("Get all collections failed!"); - println!("Cleaning up {} test collections...", collections.len()); + println!("Cleaning up test collections..."); + + let mut collection_count = 0; for collection in collections.iter() { + if !collection.name.starts_with("test_") { + continue; + } + if let Err(err) = client .collection_schemaless(&collection.name) .delete() @@ -27,9 +33,11 @@ async fn clean_test_artifacts() { { eprintln!("Failed to delete {}: {}", collection.name, err); } else { + collection_count += 1; println!("Deleted {}", collection.name); } } + println!("Deleted {} test collections.", collection_count); println!("✅ Cleanup complete."); }