From a6dfe2b3dbe61029000eaa58225ecf26b0b581a4 Mon Sep 17 00:00:00 2001 From: zhom <2717306+zhom@users.noreply.github.com> Date: Mon, 12 Oct 2026 07:01:29 +0400 Subject: [PATCH] fix: cache CLDR, steady tests --- src-tauri/src/geolocation.rs | 5 +- src-tauri/src/proxy_manager.rs | 140 ++++++++++++++++----------------- 2 files changed, 71 insertions(+), 74 deletions(-) diff --git a/src-tauri/src/geolocation.rs b/src-tauri/src/geolocation.rs index 0f590404..afd1188a 100644 --- a/src-tauri/src/geolocation.rs +++ b/src-tauri/src/geolocation.rs @@ -410,7 +410,10 @@ pub fn get_geolocation(ip: &str) -> Result { .ok_or_else(|| GeolocationError::LocationNotFound("No country code".to_string()))? .to_uppercase(); - let selector = LocaleSelector::new()?; + // The CLDR data is parsed once for the process, not on every lookup. + let selector = locale_selector().ok_or_else(|| { + GeolocationError::LocationNotFound("CLDR locale data is unavailable".to_string()) + })?; let locale = selector.from_region(&iso_code)?; Ok(Geolocation { diff --git a/src-tauri/src/proxy_manager.rs b/src-tauri/src/proxy_manager.rs index 390451d2..25223549 100644 --- a/src-tauri/src/proxy_manager.rs +++ b/src-tauri/src/proxy_manager.rs @@ -2838,6 +2838,7 @@ mod tests { use super::*; use std::env; use std::path::PathBuf; + use std::process::Stdio; use std::time::Duration; use tokio::process::Command; use tokio::time::sleep; @@ -3194,90 +3195,83 @@ mod tests { ); } - // Test the CLI detachment specifically - ensure the CLI exits properly + /// A CLI that does not detach from its worker never exits at all, so the + /// limit only has to be far past a slow start: the CLI itself waits up to + /// about four seconds for the worker, and a loaded machine adds to that. + const CLI_EXIT_LIMIT: Duration = Duration::from_secs(30); + + /// Run `donut-proxy proxy start` against a real upstream and wait for the + /// CLI to exit. Its output goes to a file, not a pipe: on macOS a pipe is + /// made close-on-exec in a second step, so a child that another test in + /// this process starts in between inherits it and keeps it open, and a + /// reader waiting for the pipe to close waits for that child instead. + async fn run_cli_start( + proxy_path: &std::path::Path, + ) -> Result<(std::process::ExitStatus, String, Duration), Box> { + let stdout = tempfile::NamedTempFile::new()?; + let mut cmd = Command::new(proxy_path); + cmd + .args([ + "proxy", + "start", + "--host", + "httpbin.org", + "--proxy-port", + "80", + "--type", + "http", + ]) + .stdin(Stdio::null()) + .stdout(Stdio::from(stdout.reopen()?)) + .stderr(Stdio::null()); + let started = std::time::Instant::now(); + let status = tokio::time::timeout(CLI_EXIT_LIMIT, cmd.status()) + .await + .map_err(|_| "CLI command timed out - this indicates improper detachment")??; + Ok(( + status, + std::fs::read_to_string(stdout.path())?, + started.elapsed(), + )) + } + + async fn stop_cli_proxy(proxy_path: &std::path::Path, stdout: &str) { + let Ok(config) = serde_json::from_str::(stdout) else { + return; + }; + if let Some(proxy_id) = config["id"].as_str() { + let _ = Command::new(proxy_path) + .args(["proxy", "stop", "--id", proxy_id]) + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status() + .await; + } + } + #[tokio::test] async fn test_cli_exits_after_proxy_start() -> Result<(), Box> { let proxy_path = ensure_donut_proxy_binary().await?; - - // Test that the CLI exits quickly with a mock upstream - let mut cmd = Command::new(&proxy_path); - cmd - .arg("proxy") - .arg("start") - .arg("--host") - .arg("httpbin.org") - .arg("--proxy-port") - .arg("80") - .arg("--type") - .arg("http"); - - let start_time = std::time::Instant::now(); - let output = tokio::time::timeout(Duration::from_secs(10), cmd.output()).await; - - match output { - Ok(Ok(cmd_output)) => { - let execution_time = start_time.elapsed(); - - if cmd_output.status.success() { - let stdout = String::from_utf8(cmd_output.stdout)?; - let config: serde_json::Value = serde_json::from_str(&stdout)?; - - // Clean up - try to stop the proxy - if let Some(proxy_id) = config["id"].as_str() { - let mut stop_cmd = Command::new(&proxy_path); - stop_cmd.arg("proxy").arg("stop").arg("--id").arg(proxy_id); - let _ = stop_cmd.output().await; - } - } - - println!("CLI detachment test passed - CLI exited in {execution_time:?}"); - } - Ok(Err(e)) => { - return Err(format!("Command execution failed: {e}").into()); - } - Err(_) => { - return Err("CLI command timed out - this indicates improper detachment".into()); - } + let (status, stdout, elapsed) = run_cli_start(&proxy_path).await?; + if status.success() { + let config: serde_json::Value = serde_json::from_str(&stdout)?; + assert!(config["id"].is_string(), "the CLI prints the started proxy"); + stop_cli_proxy(&proxy_path, &stdout).await; } - + println!("CLI detachment test passed - CLI exited in {elapsed:?}"); Ok(()) } - // Test that validates proper CLI detachment behavior #[tokio::test] async fn test_cli_detachment_behavior() -> Result<(), Box> { let proxy_path = ensure_donut_proxy_binary().await?; - - // Test that the CLI command exits quickly even with a real upstream - let mut cmd = Command::new(&proxy_path); - cmd - .arg("proxy") - .arg("start") - .arg("--host") - .arg("httpbin.org") - .arg("--proxy-port") - .arg("80") - .arg("--type") - .arg("http"); - - let output = tokio::time::timeout(Duration::from_secs(10), cmd.output()).await??; - - if output.status.success() { - let stdout = String::from_utf8(output.stdout)?; - let config: serde_json::Value = serde_json::from_str(&stdout)?; - let proxy_id = config["id"].as_str().unwrap(); - - // Clean up - let mut stop_cmd = Command::new(&proxy_path); - stop_cmd.arg("proxy").arg("stop").arg("--id").arg(proxy_id); - let _ = stop_cmd.output().await; - - println!("CLI detachment test passed"); - } else { - // Even if the upstream fails, the CLI should still exit quickly - println!("CLI command failed but exited quickly as expected"); + // Even when the upstream fails, the CLI must exit instead of waiting on + // its worker. + let (status, stdout, _) = run_cli_start(&proxy_path).await?; + if status.success() { + stop_cli_proxy(&proxy_path, &stdout).await; } - Ok(()) }