From e82ce634d6bd3bd74bd603f86d91fc635258925a Mon Sep 17 00:00:00 2001 From: Mirotin Artem Date: Mon, 15 Jun 2026 10:05:09 +0300 Subject: [PATCH] Use tokio::fs for I/O in config API tests The save and patch paths under test are async, so the tests now use tokio::fs instead of blocking std::fs. The config_store tests also switch to tempfile::tempdir() for panic-safe cleanup instead of manual remove_dir_all. --- src/api/config_edit.rs | 4 ++-- src/api/config_store.rs | 33 +++++++++++++++------------------ 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/api/config_edit.rs b/src/api/config_edit.rs index 1d583ed..3b77e18 100644 --- a/src/api/config_edit.rs +++ b/src/api/config_edit.rs @@ -333,7 +333,7 @@ mod tests { let patch: Json = serde_json::json!({"general": {"links": {"show": ["alice"]}}}); let resp = apply_patch_to_path(&path, &patch, None).await.unwrap(); assert!(resp.changed.iter().any(|c| c == "general")); - let written = std::fs::read_to_string(&path).unwrap(); + let written = tokio::fs::read_to_string(&path).await.unwrap(); let parsed: toml::Value = toml::from_str(&written).unwrap(); assert_eq!( parsed["general"]["links"]["show"][0].as_str(), @@ -353,7 +353,7 @@ mod tests { let patch: Json = serde_json::json!({"general": {"links": {"public_port": 443}}}); apply_patch_to_path(&path, &patch, None).await.unwrap(); - let written = std::fs::read_to_string(&path).unwrap(); + let written = tokio::fs::read_to_string(&path).await.unwrap(); assert!(written.contains("public_port = 443"), "{written}"); assert!(!written.contains("443.0"), "must not be a float:\n{written}"); assert!(!written.contains("\"443\""), "must not be a string:\n{written}"); diff --git a/src/api/config_store.rs b/src/api/config_store.rs index 0df1dd9..ba03ca5 100644 --- a/src/api/config_store.rs +++ b/src/api/config_store.rs @@ -520,14 +520,14 @@ mod tests { #[tokio::test] async fn save_general_section_keeps_subtables_dotted_without_duplicates() { - let dir = std::env::temp_dir().join(format!("cfgtest-{}", rand::random::())); - std::fs::create_dir_all(&dir).unwrap(); - let path = dir.join("config.toml"); - std::fs::write( + let dir = tempfile::tempdir().unwrap(); + let path = dir.path().join("config.toml"); + tokio::fs::write( &path, "[general]\nprefer_ipv6 = false\n\n[general.modes]\ntls = true\n\n\ [general.links]\npublic_host = \"old.example\"\n\n[server]\nport = 443\n", ) + .await .unwrap(); let mut cfg = ProxyConfig::default(); @@ -537,7 +537,7 @@ mod tests { .await .unwrap(); - let written = std::fs::read_to_string(&path).unwrap(); + let written = tokio::fs::read_to_string(&path).await.unwrap(); // No bare top-level [modes] / [links] headers leaked. for line in written.lines() { @@ -563,19 +563,18 @@ mod tests { .unwrap_or_else(|e| panic!("written config must parse: {e}\n{written}")); assert!(written.contains("[server]\nport = 443")); // untouched table kept - std::fs::remove_dir_all(&dir).ok(); } #[tokio::test] async fn save_general_section_is_idempotent_across_repeated_saves() { - let dir = std::env::temp_dir().join(format!("cfgtest-{}", rand::random::())); - std::fs::create_dir_all(&dir).unwrap(); - let path = dir.join("config.toml"); - std::fs::write( + let dir = tempfile::tempdir().unwrap(); + let path = dir.path().join("config.toml"); + tokio::fs::write( &path, "[general]\nprefer_ipv6 = false\n\n[general.modes]\ntls = true\n\n\ [general.links]\npublic_host = \"old.example\"\n", ) + .await .unwrap(); let mut cfg = ProxyConfig::default(); @@ -588,13 +587,12 @@ mod tests { .await .unwrap(); - let written = std::fs::read_to_string(&path).unwrap(); + let written = tokio::fs::read_to_string(&path).await.unwrap(); assert_eq!(written.matches("[general.modes]").count(), 1, "{written}"); assert_eq!(written.matches("[general.links]").count(), 1, "{written}"); assert_eq!(written.matches("[general]").count(), 1, "{written}"); toml::from_str::(&written) .unwrap_or_else(|e| panic!("written config must parse: {e}\n{written}")); - std::fs::remove_dir_all(&dir).ok(); } #[test] @@ -623,15 +621,15 @@ mod tests { #[tokio::test] async fn save_general_handles_non_contiguous_subtables() { - let dir = std::env::temp_dir().join(format!("cfgtest-{}", rand::random::())); - std::fs::create_dir_all(&dir).unwrap(); - let path = dir.join("config.toml"); + let dir = tempfile::tempdir().unwrap(); + let path = dir.path().join("config.toml"); // Hand-edited layout: [general.modes] sits AFTER an unrelated [server]. - std::fs::write( + tokio::fs::write( &path, "[general]\nprefer_ipv6 = false\n\n[server]\nport = 443\n\n\ [general.modes]\ntls = true\n", ) + .await .unwrap(); let mut cfg = ProxyConfig::default(); @@ -641,7 +639,7 @@ mod tests { .await .unwrap(); - let written = std::fs::read_to_string(&path).unwrap(); + let written = tokio::fs::read_to_string(&path).await.unwrap(); assert_eq!( written.matches("[general.modes]").count(), 1, @@ -650,7 +648,6 @@ mod tests { toml::from_str::(&written) .unwrap_or_else(|e| panic!("written config must parse: {e}\n{written}")); assert!(written.contains("[server]")); // unrelated section preserved - std::fs::remove_dir_all(&dir).ok(); } #[test]