diff --git a/crates/xtask/src/bench/workload.rs b/crates/xtask/src/bench/workload.rs index b99bf5fe4..1fe5d2ca1 100644 --- a/crates/xtask/src/bench/workload.rs +++ b/crates/xtask/src/bench/workload.rs @@ -16,7 +16,7 @@ use super::BenchDeriveArgs; use crate::common::assets::{self, Asset}; use crate::common::client::Client; use crate::common::command::{run_commands, Command}; -use crate::common::meili_process; +use crate::common::process::{self, delete_db, start_meili}; /// A bench workload. /// Not to be confused with [a test workload](crate::test::workload::Workload). @@ -128,7 +128,9 @@ async fn execute_run( binary_path: Option<&Path>, run_number: u16, ) -> anyhow::Result>> { - let meilisearch = meili_process::start( + delete_db().await; + + let meilisearch = start_meili( meili_client, master_key, &workload.extra_cli_args, @@ -148,7 +150,7 @@ async fn execute_run( ) .await?; - meili_process::kill(meilisearch).await; + process::kill_meili(meilisearch).await; tracing::info!(run_number, "Successful run"); diff --git a/crates/xtask/src/common/mod.rs b/crates/xtask/src/common/mod.rs index 1f06c9698..6d83b03c2 100644 --- a/crates/xtask/src/common/mod.rs +++ b/crates/xtask/src/common/mod.rs @@ -3,5 +3,5 @@ pub mod assets; pub mod client; pub mod command; pub mod logs; -pub mod meili_process; +pub mod process; pub mod workload; diff --git a/crates/xtask/src/common/meili_process.rs b/crates/xtask/src/common/process.rs similarity index 86% rename from crates/xtask/src/common/meili_process.rs rename to crates/xtask/src/common/process.rs index e63bd21a3..effb35184 100644 --- a/crates/xtask/src/common/meili_process.rs +++ b/crates/xtask/src/common/process.rs @@ -9,7 +9,7 @@ use tokio::time; use crate::common::client::Client; use crate::common::command::{health_command, run as run_command}; -pub async fn kill(mut meilisearch: tokio::process::Child) { +pub async fn kill_meili(mut meilisearch: tokio::process::Child) { let Some(id) = meilisearch.id() else { return }; match TokioCommand::new("kill").args(["--signal=TERM", &id.to_string()]).spawn() { @@ -65,15 +65,13 @@ async fn build() -> anyhow::Result<()> { } #[tracing::instrument(skip(client, master_key), fields(workload = _workload))] -pub async fn start( +pub async fn start_meili( client: &Client, master_key: Option<&str>, extra_cli_args: &[String], _workload: &str, binary_path: Option<&Path>, ) -> anyhow::Result { - delete_db(); - let mut command = match binary_path { Some(binary_path) => tokio::process::Command::new(binary_path), None => { @@ -103,6 +101,21 @@ pub async fn start( command.kill_on_drop(true); + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + if let Some(binary_path) = binary_path { + let mut perms = tokio::fs::metadata(binary_path) + .await + .with_context(|| format!("could not get metadata for {binary_path:?}"))? + .permissions(); + perms.set_mode(perms.mode() | 0o111); + tokio::fs::set_permissions(binary_path, perms) + .await + .with_context(|| format!("could not set permissions for {binary_path:?}"))?; + } + } + let mut meilisearch = command.spawn().context("Error starting Meilisearch")?; wait_for_health(client, &mut meilisearch).await?; @@ -139,6 +152,6 @@ async fn wait_for_health( bail!("meilisearch is not responding") } -async fn delete_db() { +pub async fn delete_db() { let _ = tokio::fs::remove_dir_all("./_xtask_benchmark.ms").await; } diff --git a/crates/xtask/src/test/versions.rs b/crates/xtask/src/test/versions.rs index 075ccf40d..53045415e 100644 --- a/crates/xtask/src/test/versions.rs +++ b/crates/xtask/src/test/versions.rs @@ -1,9 +1,67 @@ -use std::collections::BTreeMap; +use std::{collections::BTreeMap, fmt::Display, path::PathBuf}; use crate::common::assets::{Asset, AssetFormat}; use anyhow::Context; use cargo_metadata::semver::Version; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; + +#[derive(Clone)] +pub enum VersionOrLatest { + Version(Version), + Latest, +} + +impl<'a> Deserialize<'a> for VersionOrLatest { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'a>, + { + let s: &str = Deserialize::deserialize(deserializer)?; + + if s.eq_ignore_ascii_case("latest") { + Ok(VersionOrLatest::Latest) + } else { + let version = Version::parse(s).map_err(serde::de::Error::custom)?; + Ok(VersionOrLatest::Version(version)) + } + } +} + +impl Serialize for VersionOrLatest { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + VersionOrLatest::Version(v) => serializer.serialize_str(&v.to_string()), + VersionOrLatest::Latest => serializer.serialize_str("latest"), + } + } +} + +impl VersionOrLatest { + pub fn binary_path(&self, asset_folder: &str) -> anyhow::Result> { + match self { + VersionOrLatest::Version(version) => { + let mut asset_folder: PathBuf = asset_folder.parse().context("parsing asset folder")?; + let arch = get_arch()?; + let local_filename = format!("meilisearch-{version}-{arch}"); + asset_folder.push(local_filename); + Ok(Some(asset_folder)) + } + VersionOrLatest::Latest => Ok(None), + } + } +} + +impl Display for VersionOrLatest { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + VersionOrLatest::Version(v) => v.fmt(f), + VersionOrLatest::Latest => write!(f, "latest"), + } + } +} async fn get_sha256(version: &Version, asset_name: &str) -> anyhow::Result { // If version is lower than 1.15 there is no point in trying to get the sha256, GitHub didn't support it @@ -45,7 +103,7 @@ async fn get_sha256(version: &Version, asset_name: &str) -> anyhow::Result, version: &Version) -> anyhow::Result<()> { +pub fn get_arch() -> anyhow::Result<&'static str> { let arch; // linux-aarch64 @@ -82,6 +140,11 @@ async fn add_asset(assets: &mut BTreeMap, version: &Version) -> a anyhow::bail!("unsupported platform"); } + Ok(arch) +} + +async fn add_asset(assets: &mut BTreeMap, version: &Version) -> anyhow::Result<()> { + let arch = get_arch()?; let local_filename = format!("meilisearch-{version}-{arch}"); if assets.contains_key(&local_filename) { return Ok(()); diff --git a/crates/xtask/src/test/workload.rs b/crates/xtask/src/test/workload.rs index 72cd2ddfd..29563b8d0 100644 --- a/crates/xtask/src/test/workload.rs +++ b/crates/xtask/src/test/workload.rs @@ -8,45 +8,15 @@ use crate::{ assets::{fetch_assets, Asset}, client::Client, command::{run_commands, Command}, + process::{self, delete_db, kill_meili}, workload::Workload, }, - test::{versions::expand_assets_with_versions, TestDeriveArgs}, + test::{ + versions::{expand_assets_with_versions, VersionOrLatest}, + TestDeriveArgs, + }, }; -#[derive(Clone)] -pub enum VersionOrLatest { - Version(Version), - Latest, -} - -impl<'a> Deserialize<'a> for VersionOrLatest { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'a>, - { - let s: &str = Deserialize::deserialize(deserializer)?; - - if s.eq_ignore_ascii_case("latest") { - Ok(VersionOrLatest::Latest) - } else { - let version = Version::parse(s).map_err(serde::de::Error::custom)?; - Ok(VersionOrLatest::Version(version)) - } - } -} - -impl Serialize for VersionOrLatest { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - match self { - VersionOrLatest::Version(v) => serializer.serialize_str(&v.to_string()), - VersionOrLatest::Latest => serializer.serialize_str("latest"), - } - } -} - #[derive(Serialize, Deserialize)] #[serde(untagged)] pub enum CommandOrUpgrade { @@ -105,6 +75,19 @@ impl TestWorkload { expand_assets_with_versions(&mut self.assets, &all_versions).await?; fetch_assets(assets_client, &self.assets, &args.common.asset_folder).await?; + // Run server + delete_db().await; + let binary_path = VersionOrLatest::Version(self.initial_version.clone()) + .binary_path(&args.common.asset_folder)?; + let mut process = process::start_meili( + meili_client, + args.common.master_key.as_deref(), + &[], + &self.name, + binary_path.as_deref(), + ) + .await?; + let assets = Arc::new(self.assets.clone()); let return_responses = dbg!(args.add_missing_responses || args.update_responses); for command_or_upgrade in commands_or_upgrade { @@ -133,7 +116,16 @@ impl TestWorkload { } } CommandOrUpgradeVec::Upgrade(version) => { - todo!() + kill_meili(process).await; + let binary_path = version.binary_path(&args.common.asset_folder)?; + process = process::start_meili( + meili_client, + args.common.master_key.as_deref(), + &[String::from("--experimental-dumpless-upgrade")], + &self.name, + binary_path.as_deref(), + ).await?; + tracing::info!("Upgraded to {version}"); } } } diff --git a/workloads/tests/movies.json b/workloads/tests/movies.json index 90e10fa1d..c5b214984 100644 --- a/workloads/tests/movies.json +++ b/workloads/tests/movies.json @@ -28,6 +28,14 @@ ] } }, + "expectedStatus": 202, + "expectedResponse": { + "enqueuedAt": "2025-08-26T09:31:44.665991Z", + "indexUid": "movies", + "status": "enqueued", + "taskUid": 0, + "type": "settingsUpdate" + }, "synchronous": "DontWait" }, { @@ -36,6 +44,14 @@ "body": { "asset": "movies.json" }, + "expectedStatus": 202, + "expectedResponse": { + "enqueuedAt": "2025-08-26T09:31:44.732206Z", + "indexUid": "movies", + "status": "enqueued", + "taskUid": 1, + "type": "documentAdditionOrUpdate" + }, "synchronous": "WaitForTask" } ]