chore: Remove blocking read strings
This commit is contained in:
parent
bc0be9a3c1
commit
b9af601943
26 changed files with 331 additions and 243 deletions
|
|
@ -626,8 +626,8 @@ mod tests {
|
|||
assert!(!token_set.is_expiring_within(Duration::from_secs(1)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn store_roundtrip_with_encryption() {
|
||||
#[tokio::test]
|
||||
async fn store_roundtrip_with_encryption() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let store = AuthProfilesStore::new(tmp.path(), true);
|
||||
|
||||
|
|
@ -661,14 +661,14 @@ mod tests {
|
|||
Some("refresh-123")
|
||||
);
|
||||
|
||||
let raw = fs::read_to_string(store.path()).unwrap();
|
||||
let raw = tokio::fs::read_to_string(store.path()).await.unwrap();
|
||||
assert!(raw.contains("enc2:"));
|
||||
assert!(!raw.contains("refresh-123"));
|
||||
assert!(!raw.contains("access-123"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn atomic_write_replaces_file() {
|
||||
#[tokio::test]
|
||||
async fn atomic_write_replaces_file() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let store = AuthProfilesStore::new(tmp.path(), false);
|
||||
|
||||
|
|
@ -678,7 +678,7 @@ mod tests {
|
|||
let path = store.path().to_path_buf();
|
||||
assert!(path.exists());
|
||||
|
||||
let contents = fs::read_to_string(path).unwrap();
|
||||
let contents = tokio::fs::read_to_string(path).await.unwrap();
|
||||
assert!(contents.contains("\"schema_version\": 1"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3385,8 +3385,8 @@ tool_dispatcher = "xml"
|
|||
assert_eq!(parsed.agent.tool_dispatcher, "xml");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_save_and_load_tmpdir() {
|
||||
#[tokio::test]
|
||||
async fn config_save_and_load_tmpdir() {
|
||||
let dir = std::env::temp_dir().join("zeroclaw_test_config");
|
||||
let _ = fs::remove_dir_all(&dir);
|
||||
fs::create_dir_all(&dir).unwrap();
|
||||
|
|
@ -3431,7 +3431,7 @@ tool_dispatcher = "xml"
|
|||
config.save().unwrap();
|
||||
assert!(config_path.exists());
|
||||
|
||||
let contents = fs::read_to_string(&config_path).unwrap();
|
||||
let contents = tokio::fs::read_to_string(&config_path).await.unwrap();
|
||||
let loaded: Config = toml::from_str(&contents).unwrap();
|
||||
assert!(loaded
|
||||
.api_key
|
||||
|
|
@ -3446,8 +3446,8 @@ tool_dispatcher = "xml"
|
|||
let _ = fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_save_encrypts_nested_credentials() {
|
||||
#[tokio::test]
|
||||
async fn config_save_encrypts_nested_credentials() {
|
||||
let dir = std::env::temp_dir().join(format!(
|
||||
"zeroclaw_test_nested_credentials_{}",
|
||||
uuid::Uuid::new_v4()
|
||||
|
|
@ -3477,7 +3477,9 @@ tool_dispatcher = "xml"
|
|||
|
||||
config.save().unwrap();
|
||||
|
||||
let contents = fs::read_to_string(config.config_path.clone()).unwrap();
|
||||
let contents = tokio::fs::read_to_string(config.config_path.clone())
|
||||
.await
|
||||
.unwrap();
|
||||
let stored: Config = toml::from_str(&contents).unwrap();
|
||||
let store = crate::security::SecretStore::new(&dir, true);
|
||||
|
||||
|
|
@ -3527,8 +3529,8 @@ tool_dispatcher = "xml"
|
|||
let _ = fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_save_atomic_cleanup() {
|
||||
#[tokio::test]
|
||||
async fn config_save_atomic_cleanup() {
|
||||
let dir =
|
||||
std::env::temp_dir().join(format!("zeroclaw_test_config_{}", uuid::Uuid::new_v4()));
|
||||
fs::create_dir_all(&dir).unwrap();
|
||||
|
|
@ -3545,7 +3547,7 @@ tool_dispatcher = "xml"
|
|||
config.default_model = Some("model-b".into());
|
||||
config.save().unwrap();
|
||||
|
||||
let contents = fs::read_to_string(&config_path).unwrap();
|
||||
let contents = tokio::fs::read_to_string(&config_path).await.unwrap();
|
||||
assert!(contents.contains("model-b"));
|
||||
|
||||
let names: Vec<String> = fs::read_dir(&dir)
|
||||
|
|
|
|||
|
|
@ -475,13 +475,13 @@ mod tests {
|
|||
use chrono::{Duration as ChronoDuration, Utc};
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn test_config(tmp: &TempDir) -> Config {
|
||||
async fn test_config(tmp: &TempDir) -> Config {
|
||||
let config = Config {
|
||||
workspace_dir: tmp.path().join("workspace"),
|
||||
config_path: tmp.path().join("config.toml"),
|
||||
..Config::default()
|
||||
};
|
||||
std::fs::create_dir_all(&config.workspace_dir).unwrap();
|
||||
tokio::fs::create_dir_all(&config.workspace_dir).await.unwrap();
|
||||
config
|
||||
}
|
||||
|
||||
|
|
@ -513,7 +513,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn run_job_command_success() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let config = test_config(&tmp);
|
||||
let config = test_config(&tmp).await;
|
||||
let job = test_job("echo scheduler-ok");
|
||||
let security = SecurityPolicy::from_config(&config.autonomy, &config.workspace_dir);
|
||||
|
||||
|
|
@ -526,7 +526,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn run_job_command_failure() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let config = test_config(&tmp);
|
||||
let config = test_config(&tmp).await;
|
||||
let job = test_job("ls definitely_missing_file_for_scheduler_test");
|
||||
let security = SecurityPolicy::from_config(&config.autonomy, &config.workspace_dir);
|
||||
|
||||
|
|
@ -539,7 +539,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn run_job_command_times_out() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let mut config = test_config(&tmp);
|
||||
let mut config = test_config(&tmp).await;
|
||||
config.autonomy.allowed_commands = vec!["sleep".into()];
|
||||
let job = test_job("sleep 1");
|
||||
let security = SecurityPolicy::from_config(&config.autonomy, &config.workspace_dir);
|
||||
|
|
@ -553,7 +553,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn run_job_command_blocks_disallowed_command() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let mut config = test_config(&tmp);
|
||||
let mut config = test_config(&tmp).await;
|
||||
config.autonomy.allowed_commands = vec!["echo".into()];
|
||||
let job = test_job("curl https://evil.example");
|
||||
let security = SecurityPolicy::from_config(&config.autonomy, &config.workspace_dir);
|
||||
|
|
@ -567,7 +567,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn run_job_command_blocks_forbidden_path_argument() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let mut config = test_config(&tmp);
|
||||
let mut config = test_config(&tmp).await;
|
||||
config.autonomy.allowed_commands = vec!["cat".into()];
|
||||
let job = test_job("cat /etc/passwd");
|
||||
let security = SecurityPolicy::from_config(&config.autonomy, &config.workspace_dir);
|
||||
|
|
@ -582,7 +582,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn run_job_command_blocks_readonly_mode() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let mut config = test_config(&tmp);
|
||||
let mut config = test_config(&tmp).await;
|
||||
config.autonomy.level = crate::security::AutonomyLevel::ReadOnly;
|
||||
let job = test_job("echo should-not-run");
|
||||
let security = SecurityPolicy::from_config(&config.autonomy, &config.workspace_dir);
|
||||
|
|
@ -596,7 +596,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn run_job_command_blocks_rate_limited() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let mut config = test_config(&tmp);
|
||||
let mut config = test_config(&tmp).await;
|
||||
config.autonomy.max_actions_per_hour = 0;
|
||||
let job = test_job("echo should-not-run");
|
||||
let security = SecurityPolicy::from_config(&config.autonomy, &config.workspace_dir);
|
||||
|
|
@ -610,16 +610,17 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn execute_job_with_retry_recovers_after_first_failure() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let mut config = test_config(&tmp);
|
||||
let mut config = test_config(&tmp).await;
|
||||
config.reliability.scheduler_retries = 1;
|
||||
config.reliability.provider_backoff_ms = 1;
|
||||
config.autonomy.allowed_commands = vec!["sh".into()];
|
||||
let security = SecurityPolicy::from_config(&config.autonomy, &config.workspace_dir);
|
||||
|
||||
std::fs::write(
|
||||
tokio::fs::write(
|
||||
config.workspace_dir.join("retry-once.sh"),
|
||||
"#!/bin/sh\nif [ -f retry-ok.flag ]; then\n echo recovered\n exit 0\nfi\ntouch retry-ok.flag\nexit 1\n",
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let job = test_job("sh ./retry-once.sh");
|
||||
|
||||
|
|
@ -631,7 +632,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn execute_job_with_retry_exhausts_attempts() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let mut config = test_config(&tmp);
|
||||
let mut config = test_config(&tmp).await;
|
||||
config.reliability.scheduler_retries = 1;
|
||||
config.reliability.provider_backoff_ms = 1;
|
||||
let security = SecurityPolicy::from_config(&config.autonomy, &config.workspace_dir);
|
||||
|
|
@ -646,7 +647,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn run_agent_job_returns_error_without_provider_key() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let config = test_config(&tmp);
|
||||
let config = test_config(&tmp).await;
|
||||
let mut job = test_job("");
|
||||
job.job_type = JobType::Agent;
|
||||
job.prompt = Some("Say hello".into());
|
||||
|
|
@ -662,7 +663,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn persist_job_result_records_run_and_reschedules_shell_job() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let config = test_config(&tmp);
|
||||
let config = test_config(&tmp).await;
|
||||
let job = cron::add_job(&config, "*/5 * * * *", "echo ok").unwrap();
|
||||
let started = Utc::now();
|
||||
let finished = started + ChronoDuration::milliseconds(10);
|
||||
|
|
@ -679,7 +680,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn persist_job_result_success_deletes_one_shot() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let config = test_config(&tmp);
|
||||
let config = test_config(&tmp).await;
|
||||
let at = Utc::now() + ChronoDuration::minutes(10);
|
||||
let job = cron::add_agent_job(
|
||||
&config,
|
||||
|
|
@ -704,7 +705,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn persist_job_result_failure_disables_one_shot() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let config = test_config(&tmp);
|
||||
let config = test_config(&tmp).await;
|
||||
let at = Utc::now() + ChronoDuration::minutes(10);
|
||||
let job = cron::add_agent_job(
|
||||
&config,
|
||||
|
|
@ -730,7 +731,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn deliver_if_configured_handles_none_and_invalid_channel() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let config = test_config(&tmp);
|
||||
let config = test_config(&tmp).await;
|
||||
let mut job = test_job("echo ok");
|
||||
|
||||
assert!(deliver_if_configured(&config, &job, "x").await.is_ok());
|
||||
|
|
|
|||
|
|
@ -1381,8 +1381,8 @@ mod tests {
|
|||
assert_eq!(normalize_max_keys(1, 10_000), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn persist_pairing_tokens_writes_config_tokens() {
|
||||
#[tokio::test]
|
||||
async fn persist_pairing_tokens_writes_config_tokens() {
|
||||
let temp = tempfile::tempdir().unwrap();
|
||||
let config_path = temp.path().join("config.toml");
|
||||
let workspace_path = temp.path().join("workspace");
|
||||
|
|
@ -1400,7 +1400,7 @@ mod tests {
|
|||
let shared_config = Arc::new(Mutex::new(config));
|
||||
persist_pairing_tokens(&shared_config, &guard).unwrap();
|
||||
|
||||
let saved = std::fs::read_to_string(config_path).unwrap();
|
||||
let saved = tokio::fs::read_to_string(config_path).await.unwrap();
|
||||
let parsed: Config = toml::from_str(&saved).unwrap();
|
||||
assert_eq!(parsed.gateway.paired_tokens.len(), 1);
|
||||
let persisted = &parsed.gateway.paired_tokens[0];
|
||||
|
|
|
|||
|
|
@ -608,7 +608,7 @@ exit 1
|
|||
.iter()
|
||||
.any(|e| e.content.contains("Rust should stay local-first")));
|
||||
|
||||
let context_calls = fs::read_to_string(&marker).unwrap_or_default();
|
||||
let context_calls = tokio::fs::read_to_string(&marker).await.unwrap_or_default();
|
||||
assert!(
|
||||
context_calls.trim().is_empty(),
|
||||
"Expected local-hit short-circuit; got calls: {context_calls}"
|
||||
|
|
@ -669,7 +669,7 @@ exit 1
|
|||
assert!(first.is_empty());
|
||||
assert!(second.is_empty());
|
||||
|
||||
let calls = fs::read_to_string(&marker).unwrap_or_default();
|
||||
let calls = tokio::fs::read_to_string(&marker).await.unwrap_or_default();
|
||||
assert_eq!(calls.lines().count(), 1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -229,7 +229,6 @@ impl Memory for MarkdownMemory {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::fs as sync_fs;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn temp_workspace() -> (TempDir, MarkdownMemory) {
|
||||
|
|
@ -256,7 +255,7 @@ mod tests {
|
|||
mem.store("pref", "User likes Rust", MemoryCategory::Core, None)
|
||||
.await
|
||||
.unwrap();
|
||||
let content = sync_fs::read_to_string(mem.core_path()).unwrap();
|
||||
let content = fs::read_to_string(mem.core_path()).await.unwrap();
|
||||
assert!(content.contains("User likes Rust"));
|
||||
}
|
||||
|
||||
|
|
@ -267,7 +266,7 @@ mod tests {
|
|||
.await
|
||||
.unwrap();
|
||||
let path = mem.daily_path();
|
||||
let content = sync_fs::read_to_string(path).unwrap();
|
||||
let content = fs::read_to_string(path).await.unwrap();
|
||||
assert!(content.contains("Finished tests"));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4537,8 +4537,8 @@ mod tests {
|
|||
|
||||
// ── scaffold_workspace: personalization ─────────────────────
|
||||
|
||||
#[test]
|
||||
fn scaffold_bakes_user_name_into_files() {
|
||||
#[tokio::test]
|
||||
async fn scaffold_bakes_user_name_into_files() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = ProjectContext {
|
||||
user_name: "Alice".into(),
|
||||
|
|
@ -4546,21 +4546,25 @@ mod tests {
|
|||
};
|
||||
scaffold_workspace(tmp.path(), &ctx).unwrap();
|
||||
|
||||
let user_md = fs::read_to_string(tmp.path().join("USER.md")).unwrap();
|
||||
let user_md = tokio::fs::read_to_string(tmp.path().join("USER.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
user_md.contains("**Name:** Alice"),
|
||||
"USER.md should contain user name"
|
||||
);
|
||||
|
||||
let bootstrap = fs::read_to_string(tmp.path().join("BOOTSTRAP.md")).unwrap();
|
||||
let bootstrap = tokio::fs::read_to_string(tmp.path().join("BOOTSTRAP.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
bootstrap.contains("**Alice**"),
|
||||
"BOOTSTRAP.md should contain user name"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scaffold_bakes_timezone_into_files() {
|
||||
#[tokio::test]
|
||||
async fn scaffold_bakes_timezone_into_files() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = ProjectContext {
|
||||
timezone: "US/Pacific".into(),
|
||||
|
|
@ -4568,21 +4572,25 @@ mod tests {
|
|||
};
|
||||
scaffold_workspace(tmp.path(), &ctx).unwrap();
|
||||
|
||||
let user_md = fs::read_to_string(tmp.path().join("USER.md")).unwrap();
|
||||
let user_md = tokio::fs::read_to_string(tmp.path().join("USER.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
user_md.contains("**Timezone:** US/Pacific"),
|
||||
"USER.md should contain timezone"
|
||||
);
|
||||
|
||||
let bootstrap = fs::read_to_string(tmp.path().join("BOOTSTRAP.md")).unwrap();
|
||||
let bootstrap = tokio::fs::read_to_string(tmp.path().join("BOOTSTRAP.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
bootstrap.contains("US/Pacific"),
|
||||
"BOOTSTRAP.md should contain timezone"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scaffold_bakes_agent_name_into_files() {
|
||||
#[tokio::test]
|
||||
async fn scaffold_bakes_agent_name_into_files() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = ProjectContext {
|
||||
agent_name: "Crabby".into(),
|
||||
|
|
@ -4590,39 +4598,49 @@ mod tests {
|
|||
};
|
||||
scaffold_workspace(tmp.path(), &ctx).unwrap();
|
||||
|
||||
let identity = fs::read_to_string(tmp.path().join("IDENTITY.md")).unwrap();
|
||||
let identity = tokio::fs::read_to_string(tmp.path().join("IDENTITY.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
identity.contains("**Name:** Crabby"),
|
||||
"IDENTITY.md should contain agent name"
|
||||
);
|
||||
|
||||
let soul = fs::read_to_string(tmp.path().join("SOUL.md")).unwrap();
|
||||
let soul = tokio::fs::read_to_string(tmp.path().join("SOUL.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
soul.contains("You are **Crabby**"),
|
||||
"SOUL.md should contain agent name"
|
||||
);
|
||||
|
||||
let agents = fs::read_to_string(tmp.path().join("AGENTS.md")).unwrap();
|
||||
let agents = tokio::fs::read_to_string(tmp.path().join("AGENTS.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
agents.contains("Crabby Personal Assistant"),
|
||||
"AGENTS.md should contain agent name"
|
||||
);
|
||||
|
||||
let heartbeat = fs::read_to_string(tmp.path().join("HEARTBEAT.md")).unwrap();
|
||||
let heartbeat = tokio::fs::read_to_string(tmp.path().join("HEARTBEAT.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
heartbeat.contains("Crabby"),
|
||||
"HEARTBEAT.md should contain agent name"
|
||||
);
|
||||
|
||||
let bootstrap = fs::read_to_string(tmp.path().join("BOOTSTRAP.md")).unwrap();
|
||||
let bootstrap = tokio::fs::read_to_string(tmp.path().join("BOOTSTRAP.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
bootstrap.contains("Introduce yourself as Crabby"),
|
||||
"BOOTSTRAP.md should contain agent name"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scaffold_bakes_communication_style() {
|
||||
#[tokio::test]
|
||||
async fn scaffold_bakes_communication_style() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = ProjectContext {
|
||||
communication_style: "Be technical and detailed.".into(),
|
||||
|
|
@ -4630,19 +4648,25 @@ mod tests {
|
|||
};
|
||||
scaffold_workspace(tmp.path(), &ctx).unwrap();
|
||||
|
||||
let soul = fs::read_to_string(tmp.path().join("SOUL.md")).unwrap();
|
||||
let soul = tokio::fs::read_to_string(tmp.path().join("SOUL.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
soul.contains("Be technical and detailed."),
|
||||
"SOUL.md should contain communication style"
|
||||
);
|
||||
|
||||
let user_md = fs::read_to_string(tmp.path().join("USER.md")).unwrap();
|
||||
let user_md = tokio::fs::read_to_string(tmp.path().join("USER.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
user_md.contains("Be technical and detailed."),
|
||||
"USER.md should contain communication style"
|
||||
);
|
||||
|
||||
let bootstrap = fs::read_to_string(tmp.path().join("BOOTSTRAP.md")).unwrap();
|
||||
let bootstrap = tokio::fs::read_to_string(tmp.path().join("BOOTSTRAP.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
bootstrap.contains("Be technical and detailed."),
|
||||
"BOOTSTRAP.md should contain communication style"
|
||||
|
|
@ -4651,19 +4675,23 @@ mod tests {
|
|||
|
||||
// ── scaffold_workspace: defaults when context is empty ──────
|
||||
|
||||
#[test]
|
||||
fn scaffold_uses_defaults_for_empty_context() {
|
||||
#[tokio::test]
|
||||
async fn scaffold_uses_defaults_for_empty_context() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = ProjectContext::default(); // all empty
|
||||
scaffold_workspace(tmp.path(), &ctx).unwrap();
|
||||
|
||||
let identity = fs::read_to_string(tmp.path().join("IDENTITY.md")).unwrap();
|
||||
let identity = tokio::fs::read_to_string(tmp.path().join("IDENTITY.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
identity.contains("**Name:** ZeroClaw"),
|
||||
"should default agent name to ZeroClaw"
|
||||
);
|
||||
|
||||
let user_md = fs::read_to_string(tmp.path().join("USER.md")).unwrap();
|
||||
let user_md = tokio::fs::read_to_string(tmp.path().join("USER.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
user_md.contains("**Name:** User"),
|
||||
"should default user name to User"
|
||||
|
|
@ -4673,7 +4701,9 @@ mod tests {
|
|||
"should default timezone to UTC"
|
||||
);
|
||||
|
||||
let soul = fs::read_to_string(tmp.path().join("SOUL.md")).unwrap();
|
||||
let soul = tokio::fs::read_to_string(tmp.path().join("SOUL.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
soul.contains("Be warm, natural, and clear."),
|
||||
"should default communication style"
|
||||
|
|
@ -4682,8 +4712,8 @@ mod tests {
|
|||
|
||||
// ── scaffold_workspace: skip existing files ─────────────────
|
||||
|
||||
#[test]
|
||||
fn scaffold_does_not_overwrite_existing_files() {
|
||||
#[tokio::test]
|
||||
async fn scaffold_does_not_overwrite_existing_files() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = ProjectContext {
|
||||
user_name: "Bob".into(),
|
||||
|
|
@ -4697,7 +4727,7 @@ mod tests {
|
|||
scaffold_workspace(tmp.path(), &ctx).unwrap();
|
||||
|
||||
// SOUL.md should be untouched
|
||||
let soul = fs::read_to_string(&soul_path).unwrap();
|
||||
let soul = tokio::fs::read_to_string(&soul_path).await.unwrap();
|
||||
assert!(
|
||||
soul.contains("Do not overwrite me"),
|
||||
"existing files should not be overwritten"
|
||||
|
|
@ -4708,14 +4738,16 @@ mod tests {
|
|||
);
|
||||
|
||||
// But USER.md should be created fresh
|
||||
let user_md = fs::read_to_string(tmp.path().join("USER.md")).unwrap();
|
||||
let user_md = tokio::fs::read_to_string(tmp.path().join("USER.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(user_md.contains("**Name:** Bob"));
|
||||
}
|
||||
|
||||
// ── scaffold_workspace: idempotent ──────────────────────────
|
||||
|
||||
#[test]
|
||||
fn scaffold_is_idempotent() {
|
||||
#[tokio::test]
|
||||
async fn scaffold_is_idempotent() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = ProjectContext {
|
||||
user_name: "Eve".into(),
|
||||
|
|
@ -4724,19 +4756,23 @@ mod tests {
|
|||
};
|
||||
|
||||
scaffold_workspace(tmp.path(), &ctx).unwrap();
|
||||
let soul_v1 = fs::read_to_string(tmp.path().join("SOUL.md")).unwrap();
|
||||
let soul_v1 = tokio::fs::read_to_string(tmp.path().join("SOUL.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Run again — should not change anything
|
||||
scaffold_workspace(tmp.path(), &ctx).unwrap();
|
||||
let soul_v2 = fs::read_to_string(tmp.path().join("SOUL.md")).unwrap();
|
||||
let soul_v2 = tokio::fs::read_to_string(tmp.path().join("SOUL.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(soul_v1, soul_v2, "scaffold should be idempotent");
|
||||
}
|
||||
|
||||
// ── scaffold_workspace: all files are non-empty ─────────────
|
||||
|
||||
#[test]
|
||||
fn scaffold_files_are_non_empty() {
|
||||
#[tokio::test]
|
||||
async fn scaffold_files_are_non_empty() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = ProjectContext::default();
|
||||
scaffold_workspace(tmp.path(), &ctx).unwrap();
|
||||
|
|
@ -4751,20 +4787,22 @@ mod tests {
|
|||
"BOOTSTRAP.md",
|
||||
"MEMORY.md",
|
||||
] {
|
||||
let content = fs::read_to_string(tmp.path().join(f)).unwrap();
|
||||
let content = tokio::fs::read_to_string(tmp.path().join(f)).await.unwrap();
|
||||
assert!(!content.trim().is_empty(), "{f} should not be empty");
|
||||
}
|
||||
}
|
||||
|
||||
// ── scaffold_workspace: AGENTS.md references on-demand memory
|
||||
|
||||
#[test]
|
||||
fn agents_md_references_on_demand_memory() {
|
||||
#[tokio::test]
|
||||
async fn agents_md_references_on_demand_memory() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = ProjectContext::default();
|
||||
scaffold_workspace(tmp.path(), &ctx).unwrap();
|
||||
|
||||
let agents = fs::read_to_string(tmp.path().join("AGENTS.md")).unwrap();
|
||||
let agents = tokio::fs::read_to_string(tmp.path().join("AGENTS.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
agents.contains("memory_recall"),
|
||||
"AGENTS.md should reference memory_recall for on-demand access"
|
||||
|
|
@ -4777,13 +4815,15 @@ mod tests {
|
|||
|
||||
// ── scaffold_workspace: MEMORY.md warns about token cost ────
|
||||
|
||||
#[test]
|
||||
fn memory_md_warns_about_token_cost() {
|
||||
#[tokio::test]
|
||||
async fn memory_md_warns_about_token_cost() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = ProjectContext::default();
|
||||
scaffold_workspace(tmp.path(), &ctx).unwrap();
|
||||
|
||||
let memory = fs::read_to_string(tmp.path().join("MEMORY.md")).unwrap();
|
||||
let memory = tokio::fs::read_to_string(tmp.path().join("MEMORY.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
memory.contains("costs tokens"),
|
||||
"MEMORY.md should warn about token cost"
|
||||
|
|
@ -4796,13 +4836,15 @@ mod tests {
|
|||
|
||||
// ── scaffold_workspace: TOOLS.md lists memory_forget ────────
|
||||
|
||||
#[test]
|
||||
fn tools_md_lists_all_builtin_tools() {
|
||||
#[tokio::test]
|
||||
async fn tools_md_lists_all_builtin_tools() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = ProjectContext::default();
|
||||
scaffold_workspace(tmp.path(), &ctx).unwrap();
|
||||
|
||||
let tools = fs::read_to_string(tmp.path().join("TOOLS.md")).unwrap();
|
||||
let tools = tokio::fs::read_to_string(tmp.path().join("TOOLS.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
for tool in &[
|
||||
"shell",
|
||||
"file_read",
|
||||
|
|
@ -4826,13 +4868,15 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn soul_md_includes_emoji_awareness_guidance() {
|
||||
#[tokio::test]
|
||||
async fn soul_md_includes_emoji_awareness_guidance() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = ProjectContext::default();
|
||||
scaffold_workspace(tmp.path(), &ctx).unwrap();
|
||||
|
||||
let soul = fs::read_to_string(tmp.path().join("SOUL.md")).unwrap();
|
||||
let soul = tokio::fs::read_to_string(tmp.path().join("SOUL.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
soul.contains("Use emojis naturally (0-2 max"),
|
||||
"SOUL.md should include emoji usage guidance"
|
||||
|
|
@ -4845,8 +4889,8 @@ mod tests {
|
|||
|
||||
// ── scaffold_workspace: special characters in names ─────────
|
||||
|
||||
#[test]
|
||||
fn scaffold_handles_special_characters_in_names() {
|
||||
#[tokio::test]
|
||||
async fn scaffold_handles_special_characters_in_names() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = ProjectContext {
|
||||
user_name: "José María".into(),
|
||||
|
|
@ -4856,17 +4900,21 @@ mod tests {
|
|||
};
|
||||
scaffold_workspace(tmp.path(), &ctx).unwrap();
|
||||
|
||||
let user_md = fs::read_to_string(tmp.path().join("USER.md")).unwrap();
|
||||
let user_md = tokio::fs::read_to_string(tmp.path().join("USER.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(user_md.contains("José María"));
|
||||
|
||||
let soul = fs::read_to_string(tmp.path().join("SOUL.md")).unwrap();
|
||||
let soul = tokio::fs::read_to_string(tmp.path().join("SOUL.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(soul.contains("ZeroClaw-v2"));
|
||||
}
|
||||
|
||||
// ── scaffold_workspace: full personalization round-trip ─────
|
||||
|
||||
#[test]
|
||||
fn scaffold_full_personalization() {
|
||||
#[tokio::test]
|
||||
async fn scaffold_full_personalization() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let ctx = ProjectContext {
|
||||
user_name: "Argenis".into(),
|
||||
|
|
@ -4879,27 +4927,39 @@ mod tests {
|
|||
scaffold_workspace(tmp.path(), &ctx).unwrap();
|
||||
|
||||
// Verify every file got personalized
|
||||
let identity = fs::read_to_string(tmp.path().join("IDENTITY.md")).unwrap();
|
||||
let identity = tokio::fs::read_to_string(tmp.path().join("IDENTITY.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(identity.contains("**Name:** Claw"));
|
||||
|
||||
let soul = fs::read_to_string(tmp.path().join("SOUL.md")).unwrap();
|
||||
let soul = tokio::fs::read_to_string(tmp.path().join("SOUL.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(soul.contains("You are **Claw**"));
|
||||
assert!(soul.contains("Be friendly, human, and conversational"));
|
||||
|
||||
let user_md = fs::read_to_string(tmp.path().join("USER.md")).unwrap();
|
||||
let user_md = tokio::fs::read_to_string(tmp.path().join("USER.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(user_md.contains("**Name:** Argenis"));
|
||||
assert!(user_md.contains("**Timezone:** US/Eastern"));
|
||||
assert!(user_md.contains("Be friendly, human, and conversational"));
|
||||
|
||||
let agents = fs::read_to_string(tmp.path().join("AGENTS.md")).unwrap();
|
||||
let agents = tokio::fs::read_to_string(tmp.path().join("AGENTS.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(agents.contains("Claw Personal Assistant"));
|
||||
|
||||
let bootstrap = fs::read_to_string(tmp.path().join("BOOTSTRAP.md")).unwrap();
|
||||
let bootstrap = tokio::fs::read_to_string(tmp.path().join("BOOTSTRAP.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(bootstrap.contains("**Argenis**"));
|
||||
assert!(bootstrap.contains("US/Eastern"));
|
||||
assert!(bootstrap.contains("Introduce yourself as Claw"));
|
||||
|
||||
let heartbeat = fs::read_to_string(tmp.path().join("HEARTBEAT.md")).unwrap();
|
||||
let heartbeat = tokio::fs::read_to_string(tmp.path().join("HEARTBEAT.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(heartbeat.contains("Claw"));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ impl Tool for ArduinoUploadTool {
|
|||
let sketch_dir = temp_dir.join(sketch_name);
|
||||
let ino_path = sketch_dir.join(format!("{}.ino", sketch_name));
|
||||
|
||||
if let Err(e) = std::fs::create_dir_all(&sketch_dir) {
|
||||
if let Err(e) = tokio::fs::create_dir_all(&sketch_dir).await {
|
||||
return Ok(ToolResult {
|
||||
success: false,
|
||||
output: format!("Failed to create sketch dir: {}", e),
|
||||
|
|
@ -83,8 +83,8 @@ impl Tool for ArduinoUploadTool {
|
|||
});
|
||||
}
|
||||
|
||||
if let Err(e) = std::fs::write(&ino_path, code) {
|
||||
let _ = std::fs::remove_dir_all(&temp_dir);
|
||||
if let Err(e) = tokio::fs::write(&ino_path, code).await {
|
||||
let _ = tokio::fs::remove_dir_all(&temp_dir).await;
|
||||
return Ok(ToolResult {
|
||||
success: false,
|
||||
output: format!("Failed to write sketch: {}", e),
|
||||
|
|
@ -103,7 +103,7 @@ impl Tool for ArduinoUploadTool {
|
|||
let compile_output = match compile {
|
||||
Ok(o) => o,
|
||||
Err(e) => {
|
||||
let _ = std::fs::remove_dir_all(&temp_dir);
|
||||
let _ = tokio::fs::remove_dir_all(&temp_dir).await;
|
||||
return Ok(ToolResult {
|
||||
success: false,
|
||||
output: format!("arduino-cli compile failed: {}", e),
|
||||
|
|
@ -114,7 +114,7 @@ impl Tool for ArduinoUploadTool {
|
|||
|
||||
if !compile_output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&compile_output.stderr);
|
||||
let _ = std::fs::remove_dir_all(&temp_dir);
|
||||
let _ = tokio::fs::remove_dir_all(&temp_dir).await;
|
||||
return Ok(ToolResult {
|
||||
success: false,
|
||||
output: format!("Compile failed:\n{}", stderr),
|
||||
|
|
@ -130,7 +130,7 @@ impl Tool for ArduinoUploadTool {
|
|||
let upload_output = match upload {
|
||||
Ok(o) => o,
|
||||
Err(e) => {
|
||||
let _ = std::fs::remove_dir_all(&temp_dir);
|
||||
let _ = tokio::fs::remove_dir_all(&temp_dir).await;
|
||||
return Ok(ToolResult {
|
||||
success: false,
|
||||
output: format!("arduino-cli upload failed: {}", e),
|
||||
|
|
@ -139,7 +139,7 @@ impl Tool for ArduinoUploadTool {
|
|||
}
|
||||
};
|
||||
|
||||
let _ = std::fs::remove_dir_all(&temp_dir);
|
||||
let _ = tokio::fs::remove_dir_all(&temp_dir).await;
|
||||
|
||||
if !upload_output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&upload_output.stderr);
|
||||
|
|
|
|||
|
|
@ -1054,7 +1054,10 @@ impl Provider for OpenAiCompatibleProvider {
|
|||
|
||||
let url = self.chat_completions_url();
|
||||
let response = self
|
||||
.apply_auth_header(self.http_client().post(&url).json(&native_request), credential)
|
||||
.apply_auth_header(
|
||||
self.http_client().post(&url).json(&native_request),
|
||||
credential,
|
||||
)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
|
|
|
|||
|
|
@ -45,14 +45,12 @@ fn is_non_retryable(err: &anyhow::Error) -> bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
let model_catalog_mismatch = msg_lower.contains("model")
|
||||
msg_lower.contains("model")
|
||||
&& (msg_lower.contains("not found")
|
||||
|| msg_lower.contains("unknown")
|
||||
|| msg_lower.contains("unsupported")
|
||||
|| msg_lower.contains("does not exist")
|
||||
|| msg_lower.contains("invalid"));
|
||||
|
||||
model_catalog_mismatch
|
||||
|| msg_lower.contains("invalid"))
|
||||
}
|
||||
|
||||
/// Check if an error is a rate-limit (429) error.
|
||||
|
|
|
|||
|
|
@ -335,8 +335,8 @@ mod tests {
|
|||
|
||||
// ── §8.1 Log rotation tests ─────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn audit_logger_writes_event_when_enabled() -> Result<()> {
|
||||
#[tokio::test]
|
||||
async fn audit_logger_writes_event_when_enabled() -> Result<()> {
|
||||
let tmp = TempDir::new()?;
|
||||
let config = AuditConfig {
|
||||
enabled: true,
|
||||
|
|
@ -353,7 +353,7 @@ mod tests {
|
|||
let log_path = tmp.path().join("audit.log");
|
||||
assert!(log_path.exists(), "audit log file must be created");
|
||||
|
||||
let content = std::fs::read_to_string(&log_path)?;
|
||||
let content = tokio::fs::read_to_string(&log_path).await?;
|
||||
assert!(!content.is_empty(), "audit log must not be empty");
|
||||
|
||||
let parsed: AuditEvent = serde_json::from_str(content.trim())?;
|
||||
|
|
@ -361,8 +361,8 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn audit_log_command_event_writes_structured_entry() -> Result<()> {
|
||||
#[tokio::test]
|
||||
async fn audit_log_command_event_writes_structured_entry() -> Result<()> {
|
||||
let tmp = TempDir::new()?;
|
||||
let config = AuditConfig {
|
||||
enabled: true,
|
||||
|
|
@ -382,7 +382,7 @@ mod tests {
|
|||
})?;
|
||||
|
||||
let log_path = tmp.path().join("audit.log");
|
||||
let content = std::fs::read_to_string(&log_path)?;
|
||||
let content = tokio::fs::read_to_string(&log_path).await?;
|
||||
let parsed: AuditEvent = serde_json::from_str(content.trim())?;
|
||||
|
||||
let action = parsed.action.unwrap();
|
||||
|
|
|
|||
|
|
@ -334,8 +334,8 @@ mod tests {
|
|||
assert!(!SecretStore::is_encrypted(""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn key_file_created_on_first_encrypt() {
|
||||
#[tokio::test]
|
||||
async fn key_file_created_on_first_encrypt() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let store = SecretStore::new(tmp.path(), true);
|
||||
assert!(!store.key_path.exists());
|
||||
|
|
@ -343,7 +343,7 @@ mod tests {
|
|||
store.encrypt("test").unwrap();
|
||||
assert!(store.key_path.exists(), "Key file should be created");
|
||||
|
||||
let key_hex = fs::read_to_string(&store.key_path).unwrap();
|
||||
let key_hex = tokio::fs::read_to_string(&store.key_path).await.unwrap();
|
||||
assert_eq!(
|
||||
key_hex.len(),
|
||||
KEY_LEN * 2,
|
||||
|
|
|
|||
|
|
@ -191,8 +191,8 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn integrate_creates_files() {
|
||||
#[tokio::test]
|
||||
async fn integrate_creates_files() {
|
||||
let tmp = std::env::temp_dir().join("zeroclaw-test-integrate");
|
||||
let _ = fs::remove_dir_all(&tmp);
|
||||
|
||||
|
|
@ -203,11 +203,15 @@ mod tests {
|
|||
assert!(path.join("SKILL.toml").exists());
|
||||
assert!(path.join("SKILL.md").exists());
|
||||
|
||||
let toml = fs::read_to_string(path.join("SKILL.toml")).unwrap();
|
||||
let toml = tokio::fs::read_to_string(path.join("SKILL.toml"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(toml.contains("name = \"test-skill\""));
|
||||
assert!(toml.contains("stars = 42"));
|
||||
|
||||
let md = fs::read_to_string(path.join("SKILL.md")).unwrap();
|
||||
let md = tokio::fs::read_to_string(path.join("SKILL.md"))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(md.contains("# test-skill"));
|
||||
assert!(md.contains("A test skill for unit tests"));
|
||||
|
||||
|
|
|
|||
|
|
@ -4,21 +4,21 @@ mod tests {
|
|||
use std::path::Path;
|
||||
use tempfile::TempDir;
|
||||
|
||||
#[test]
|
||||
fn test_skills_symlink_unix_edge_cases() {
|
||||
#[tokio::test]
|
||||
async fn test_skills_symlink_unix_edge_cases() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let workspace_dir = tmp.path().join("workspace");
|
||||
std::fs::create_dir_all(&workspace_dir).unwrap();
|
||||
tokio::fs::create_dir_all(&workspace_dir).await.unwrap();
|
||||
|
||||
let skills_path = skills_dir(&workspace_dir);
|
||||
std::fs::create_dir_all(&skills_path).unwrap();
|
||||
tokio::fs::create_dir_all(&skills_path).await.unwrap();
|
||||
|
||||
// Test case 1: Valid symlink creation on Unix
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let source_dir = tmp.path().join("source_skill");
|
||||
std::fs::create_dir_all(&source_dir).unwrap();
|
||||
std::fs::write(source_dir.join("SKILL.md"), "# Test Skill\nContent").unwrap();
|
||||
tokio::fs::create_dir_all(&source_dir).await.unwrap();
|
||||
tokio::fs::write(source_dir.join("SKILL.md"), "# Test Skill\nContent").await.unwrap();
|
||||
|
||||
let dest_link = skills_path.join("linked_skill");
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ mod tests {
|
|||
assert!(dest_link.is_symlink());
|
||||
|
||||
// Verify we can read through symlink
|
||||
let content = std::fs::read_to_string(dest_link.join("SKILL.md"));
|
||||
let content = tokio::fs::read_to_string(dest_link.join("SKILL.md")).await;
|
||||
assert!(content.is_ok());
|
||||
assert!(content.unwrap().contains("Test Skill"));
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ mod tests {
|
|||
);
|
||||
|
||||
// But reading through it should fail
|
||||
let content = std::fs::read_to_string(broken_link.join("SKILL.md"));
|
||||
let content = tokio::fs::read_to_string(broken_link.join("SKILL.md")).await;
|
||||
assert!(content.is_err());
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ mod tests {
|
|||
#[cfg(windows)]
|
||||
{
|
||||
let source_dir = tmp.path().join("source_skill");
|
||||
std::fs::create_dir_all(&source_dir).unwrap();
|
||||
tokio::fs::create_dir_all(&source_dir).await.unwrap();
|
||||
|
||||
let dest_link = skills_path.join("linked_skill");
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ mod tests {
|
|||
assert!(!dest_link.exists());
|
||||
} else {
|
||||
// Clean up if it succeeded
|
||||
let _ = std::fs::remove_dir(&dest_link);
|
||||
let _ = tokio::fs::remove_dir(&dest_link).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -80,21 +80,21 @@ mod tests {
|
|||
assert!(!empty_skills_path.exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_skills_symlink_permissions_and_safety() {
|
||||
#[tokio::test]
|
||||
async fn test_skills_symlink_permissions_and_safety() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let workspace_dir = tmp.path().join("workspace");
|
||||
std::fs::create_dir_all(&workspace_dir).unwrap();
|
||||
tokio::fs::create_dir_all(&workspace_dir).await.unwrap();
|
||||
|
||||
let skills_path = skills_dir(&workspace_dir);
|
||||
std::fs::create_dir_all(&skills_path).unwrap();
|
||||
tokio::fs::create_dir_all(&skills_path).await.unwrap();
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
// Test case: Symlink outside workspace should be allowed (user responsibility)
|
||||
let outside_dir = tmp.path().join("outside_skill");
|
||||
std::fs::create_dir_all(&outside_dir).unwrap();
|
||||
std::fs::write(outside_dir.join("SKILL.md"), "# Outside Skill\nContent").unwrap();
|
||||
tokio::fs::create_dir_all(&outside_dir).await.unwrap();
|
||||
tokio::fs::write(outside_dir.join("SKILL.md"), "# Outside Skill\nContent").await.unwrap();
|
||||
|
||||
let dest_link = skills_path.join("outside_skill");
|
||||
let result = std::os::unix::fs::symlink(&outside_dir, &dest_link);
|
||||
|
|
@ -104,7 +104,7 @@ mod tests {
|
|||
);
|
||||
|
||||
// Should still be readable
|
||||
let content = std::fs::read_to_string(dest_link.join("SKILL.md"));
|
||||
let content = tokio::fs::read_to_string(dest_link.join("SKILL.md")).await;
|
||||
assert!(content.is_ok());
|
||||
assert!(content.unwrap().contains("Outside Skill"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1225,8 +1225,9 @@ mod native_backend {
|
|||
});
|
||||
|
||||
if let Some(path_str) = path {
|
||||
std::fs::write(&path_str, &png)
|
||||
.with_context(|| format!("Failed to write screenshot to {path_str}"))?;
|
||||
tokio::fs::write(&path_str, &png).await.with_context(|| {
|
||||
format!("Failed to write screenshot to {path_str}")
|
||||
})?;
|
||||
payload["path"] = Value::String(path_str);
|
||||
} else {
|
||||
payload["png_base64"] =
|
||||
|
|
|
|||
|
|
@ -217,13 +217,13 @@ mod tests {
|
|||
use crate::security::AutonomyLevel;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn test_config(tmp: &TempDir) -> Arc<Config> {
|
||||
async fn test_config(tmp: &TempDir) -> Arc<Config> {
|
||||
let config = Config {
|
||||
workspace_dir: tmp.path().join("workspace"),
|
||||
config_path: tmp.path().join("config.toml"),
|
||||
..Config::default()
|
||||
};
|
||||
std::fs::create_dir_all(&config.workspace_dir).unwrap();
|
||||
tokio::fs::create_dir_all(&config.workspace_dir).await.unwrap();
|
||||
Arc::new(config)
|
||||
}
|
||||
|
||||
|
|
@ -237,7 +237,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn adds_shell_job() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let cfg = test_config(&tmp);
|
||||
let cfg = test_config(&tmp).await;
|
||||
let tool = CronAddTool::new(cfg.clone(), test_security(&cfg));
|
||||
let result = tool
|
||||
.execute(json!({
|
||||
|
|
@ -262,7 +262,7 @@ mod tests {
|
|||
};
|
||||
config.autonomy.allowed_commands = vec!["echo".into()];
|
||||
config.autonomy.level = AutonomyLevel::Supervised;
|
||||
std::fs::create_dir_all(&config.workspace_dir).unwrap();
|
||||
tokio::fs::create_dir_all(&config.workspace_dir).await.unwrap();
|
||||
let cfg = Arc::new(config);
|
||||
let tool = CronAddTool::new(cfg.clone(), test_security(&cfg));
|
||||
|
||||
|
|
@ -285,7 +285,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn rejects_invalid_schedule() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let cfg = test_config(&tmp);
|
||||
let cfg = test_config(&tmp).await;
|
||||
let tool = CronAddTool::new(cfg.clone(), test_security(&cfg));
|
||||
|
||||
let result = tool
|
||||
|
|
@ -307,7 +307,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn agent_job_requires_prompt() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let cfg = test_config(&tmp);
|
||||
let cfg = test_config(&tmp).await;
|
||||
let tool = CronAddTool::new(cfg.clone(), test_security(&cfg));
|
||||
|
||||
let result = tool
|
||||
|
|
|
|||
|
|
@ -63,20 +63,20 @@ mod tests {
|
|||
use crate::config::Config;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn test_config(tmp: &TempDir) -> Arc<Config> {
|
||||
async fn test_config(tmp: &TempDir) -> Arc<Config> {
|
||||
let config = Config {
|
||||
workspace_dir: tmp.path().join("workspace"),
|
||||
config_path: tmp.path().join("config.toml"),
|
||||
..Config::default()
|
||||
};
|
||||
std::fs::create_dir_all(&config.workspace_dir).unwrap();
|
||||
tokio::fs::create_dir_all(&config.workspace_dir).await.unwrap();
|
||||
Arc::new(config)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn returns_empty_list_when_no_jobs() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let cfg = test_config(&tmp);
|
||||
let cfg = test_config(&tmp).await;
|
||||
let tool = CronListTool::new(cfg);
|
||||
|
||||
let result = tool.execute(json!({})).await.unwrap();
|
||||
|
|
@ -87,7 +87,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn errors_when_cron_disabled() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let mut cfg = (*test_config(&tmp)).clone();
|
||||
let mut cfg = (*test_config(&tmp).await).clone();
|
||||
cfg.cron.enabled = false;
|
||||
let tool = CronListTool::new(Arc::new(cfg));
|
||||
|
||||
|
|
|
|||
|
|
@ -76,20 +76,20 @@ mod tests {
|
|||
use crate::config::Config;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn test_config(tmp: &TempDir) -> Arc<Config> {
|
||||
async fn test_config(tmp: &TempDir) -> Arc<Config> {
|
||||
let config = Config {
|
||||
workspace_dir: tmp.path().join("workspace"),
|
||||
config_path: tmp.path().join("config.toml"),
|
||||
..Config::default()
|
||||
};
|
||||
std::fs::create_dir_all(&config.workspace_dir).unwrap();
|
||||
tokio::fs::create_dir_all(&config.workspace_dir).await.unwrap();
|
||||
Arc::new(config)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn removes_existing_job() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let cfg = test_config(&tmp);
|
||||
let cfg = test_config(&tmp).await;
|
||||
let job = cron::add_job(&cfg, "*/5 * * * *", "echo ok").unwrap();
|
||||
let tool = CronRemoveTool::new(cfg.clone());
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn errors_when_job_id_missing() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let cfg = test_config(&tmp);
|
||||
let cfg = test_config(&tmp).await;
|
||||
let tool = CronRemoveTool::new(cfg);
|
||||
|
||||
let result = tool.execute(json!({})).await.unwrap();
|
||||
|
|
|
|||
|
|
@ -107,20 +107,20 @@ mod tests {
|
|||
use crate::config::Config;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn test_config(tmp: &TempDir) -> Arc<Config> {
|
||||
async fn test_config(tmp: &TempDir) -> Arc<Config> {
|
||||
let config = Config {
|
||||
workspace_dir: tmp.path().join("workspace"),
|
||||
config_path: tmp.path().join("config.toml"),
|
||||
..Config::default()
|
||||
};
|
||||
std::fs::create_dir_all(&config.workspace_dir).unwrap();
|
||||
tokio::fs::create_dir_all(&config.workspace_dir).await.unwrap();
|
||||
Arc::new(config)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn force_runs_job_and_records_history() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let cfg = test_config(&tmp);
|
||||
let cfg = test_config(&tmp).await;
|
||||
let job = cron::add_job(&cfg, "*/5 * * * *", "echo run-now").unwrap();
|
||||
let tool = CronRunTool::new(cfg.clone());
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn errors_for_missing_job() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let cfg = test_config(&tmp);
|
||||
let cfg = test_config(&tmp).await;
|
||||
let tool = CronRunTool::new(cfg);
|
||||
|
||||
let result = tool
|
||||
|
|
|
|||
|
|
@ -121,20 +121,20 @@ mod tests {
|
|||
use chrono::{Duration as ChronoDuration, Utc};
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn test_config(tmp: &TempDir) -> Arc<Config> {
|
||||
async fn test_config(tmp: &TempDir) -> Arc<Config> {
|
||||
let config = Config {
|
||||
workspace_dir: tmp.path().join("workspace"),
|
||||
config_path: tmp.path().join("config.toml"),
|
||||
..Config::default()
|
||||
};
|
||||
std::fs::create_dir_all(&config.workspace_dir).unwrap();
|
||||
tokio::fs::create_dir_all(&config.workspace_dir).await.unwrap();
|
||||
Arc::new(config)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn lists_runs_with_truncation() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let cfg = test_config(&tmp);
|
||||
let cfg = test_config(&tmp).await;
|
||||
let job = cron::add_job(&cfg, "*/5 * * * *", "echo ok").unwrap();
|
||||
|
||||
let long_output = "x".repeat(1000);
|
||||
|
|
@ -163,7 +163,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn errors_when_job_id_missing() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let cfg = test_config(&tmp);
|
||||
let cfg = test_config(&tmp).await;
|
||||
let tool = CronRunsTool::new(cfg);
|
||||
let result = tool.execute(json!({})).await.unwrap();
|
||||
assert!(!result.success);
|
||||
|
|
|
|||
|
|
@ -111,13 +111,13 @@ mod tests {
|
|||
use crate::config::Config;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn test_config(tmp: &TempDir) -> Arc<Config> {
|
||||
async fn test_config(tmp: &TempDir) -> Arc<Config> {
|
||||
let config = Config {
|
||||
workspace_dir: tmp.path().join("workspace"),
|
||||
config_path: tmp.path().join("config.toml"),
|
||||
..Config::default()
|
||||
};
|
||||
std::fs::create_dir_all(&config.workspace_dir).unwrap();
|
||||
tokio::fs::create_dir_all(&config.workspace_dir).await.unwrap();
|
||||
Arc::new(config)
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn updates_enabled_flag() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let cfg = test_config(&tmp);
|
||||
let cfg = test_config(&tmp).await;
|
||||
let job = cron::add_job(&cfg, "*/5 * * * *", "echo ok").unwrap();
|
||||
let tool = CronUpdateTool::new(cfg.clone(), test_security(&cfg));
|
||||
|
||||
|
|
@ -156,7 +156,7 @@ mod tests {
|
|||
..Config::default()
|
||||
};
|
||||
config.autonomy.allowed_commands = vec!["echo".into()];
|
||||
std::fs::create_dir_all(&config.workspace_dir).unwrap();
|
||||
tokio::fs::create_dir_all(&config.workspace_dir).await.unwrap();
|
||||
let cfg = Arc::new(config);
|
||||
let job = cron::add_job(&cfg, "*/5 * * * *", "echo ok").unwrap();
|
||||
let tool = CronUpdateTool::new(cfg.clone(), test_security(&cfg));
|
||||
|
|
|
|||
|
|
@ -428,7 +428,7 @@ mod tests {
|
|||
async fn execute_real_file() {
|
||||
// Create a minimal valid PNG
|
||||
let dir = std::env::temp_dir().join("zeroclaw_image_info_test");
|
||||
let _ = std::fs::create_dir_all(&dir);
|
||||
let _ = tokio::fs::create_dir_all(&dir).await;
|
||||
let png_path = dir.join("test.png");
|
||||
|
||||
// Minimal 1x1 red PNG (67 bytes)
|
||||
|
|
@ -448,7 +448,7 @@ mod tests {
|
|||
0x49, 0x45, 0x4E, 0x44, // IEND
|
||||
0xAE, 0x42, 0x60, 0x82, // CRC
|
||||
];
|
||||
std::fs::write(&png_path, &png_bytes).unwrap();
|
||||
tokio::fs::write(&png_path, &png_bytes).await.unwrap();
|
||||
|
||||
let tool = ImageInfoTool::new(test_security());
|
||||
let result = tool
|
||||
|
|
@ -461,13 +461,13 @@ mod tests {
|
|||
assert!(!result.output.contains("data:"));
|
||||
|
||||
// Clean up
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
let _ = tokio::fs::remove_dir_all(&dir).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn execute_with_base64() {
|
||||
let dir = std::env::temp_dir().join("zeroclaw_image_info_b64");
|
||||
let _ = std::fs::create_dir_all(&dir);
|
||||
let _ = tokio::fs::create_dir_all(&dir).await;
|
||||
let png_path = dir.join("test_b64.png");
|
||||
|
||||
// Minimal 1x1 PNG
|
||||
|
|
@ -478,7 +478,7 @@ mod tests {
|
|||
0xD7, 0x63, 0xF8, 0xCF, 0xC0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0xE2, 0x21, 0xBC,
|
||||
0x33, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82,
|
||||
];
|
||||
std::fs::write(&png_path, &png_bytes).unwrap();
|
||||
tokio::fs::write(&png_path, &png_bytes).await.unwrap();
|
||||
|
||||
let tool = ImageInfoTool::new(test_security());
|
||||
let result = tool
|
||||
|
|
@ -488,6 +488,6 @@ mod tests {
|
|||
assert!(result.success);
|
||||
assert!(result.output.contains("data:image/png;base64,"));
|
||||
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
let _ = tokio::fs::remove_dir_all(&dir).await;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,9 +41,10 @@ impl PushoverTool {
|
|||
)
|
||||
}
|
||||
|
||||
fn get_credentials(&self) -> anyhow::Result<(String, String)> {
|
||||
async fn get_credentials(&self) -> anyhow::Result<(String, String)> {
|
||||
let env_path = self.workspace_dir.join(".env");
|
||||
let content = std::fs::read_to_string(&env_path)
|
||||
let content = tokio::fs::read_to_string(&env_path)
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("Failed to read {}: {}", env_path.display(), e))?;
|
||||
|
||||
let mut token = None;
|
||||
|
|
@ -153,7 +154,7 @@ impl Tool for PushoverTool {
|
|||
|
||||
let sound = args.get("sound").and_then(|v| v.as_str()).map(String::from);
|
||||
|
||||
let (token, user_key) = self.get_credentials()?;
|
||||
let (token, user_key) = self.get_credentials().await?;
|
||||
|
||||
let mut form = reqwest::multipart::Form::new()
|
||||
.text("token", token)
|
||||
|
|
@ -269,8 +270,8 @@ mod tests {
|
|||
assert!(required.contains(&serde_json::Value::String("message".to_string())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn credentials_parsed_from_env_file() {
|
||||
#[tokio::test]
|
||||
async fn credentials_parsed_from_env_file() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let env_path = tmp.path().join(".env");
|
||||
fs::write(
|
||||
|
|
@ -283,7 +284,7 @@ mod tests {
|
|||
test_security(AutonomyLevel::Full, 100),
|
||||
tmp.path().to_path_buf(),
|
||||
);
|
||||
let result = tool.get_credentials();
|
||||
let result = tool.get_credentials().await;
|
||||
|
||||
assert!(result.is_ok());
|
||||
let (token, user_key) = result.unwrap();
|
||||
|
|
@ -291,20 +292,20 @@ mod tests {
|
|||
assert_eq!(user_key, "userkey456");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn credentials_fail_without_env_file() {
|
||||
#[tokio::test]
|
||||
async fn credentials_fail_without_env_file() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let tool = PushoverTool::new(
|
||||
test_security(AutonomyLevel::Full, 100),
|
||||
tmp.path().to_path_buf(),
|
||||
);
|
||||
let result = tool.get_credentials();
|
||||
let result = tool.get_credentials().await;
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn credentials_fail_without_token() {
|
||||
#[tokio::test]
|
||||
async fn credentials_fail_without_token() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let env_path = tmp.path().join(".env");
|
||||
fs::write(&env_path, "PUSHOVER_USER_KEY=userkey456\n").unwrap();
|
||||
|
|
@ -313,13 +314,13 @@ mod tests {
|
|||
test_security(AutonomyLevel::Full, 100),
|
||||
tmp.path().to_path_buf(),
|
||||
);
|
||||
let result = tool.get_credentials();
|
||||
let result = tool.get_credentials().await;
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn credentials_fail_without_user_key() {
|
||||
#[tokio::test]
|
||||
async fn credentials_fail_without_user_key() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let env_path = tmp.path().join(".env");
|
||||
fs::write(&env_path, "PUSHOVER_TOKEN=testtoken123\n").unwrap();
|
||||
|
|
@ -328,13 +329,13 @@ mod tests {
|
|||
test_security(AutonomyLevel::Full, 100),
|
||||
tmp.path().to_path_buf(),
|
||||
);
|
||||
let result = tool.get_credentials();
|
||||
let result = tool.get_credentials().await;
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn credentials_ignore_comments() {
|
||||
#[tokio::test]
|
||||
async fn credentials_ignore_comments() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let env_path = tmp.path().join(".env");
|
||||
fs::write(&env_path, "# This is a comment\nPUSHOVER_TOKEN=realtoken\n# Another comment\nPUSHOVER_USER_KEY=realuser\n").unwrap();
|
||||
|
|
@ -343,7 +344,7 @@ mod tests {
|
|||
test_security(AutonomyLevel::Full, 100),
|
||||
tmp.path().to_path_buf(),
|
||||
);
|
||||
let result = tool.get_credentials();
|
||||
let result = tool.get_credentials().await;
|
||||
|
||||
assert!(result.is_ok());
|
||||
let (token, user_key) = result.unwrap();
|
||||
|
|
@ -371,8 +372,8 @@ mod tests {
|
|||
assert!(schema["properties"].get("sound").is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn credentials_support_export_and_quoted_values() {
|
||||
#[tokio::test]
|
||||
async fn credentials_support_export_and_quoted_values() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let env_path = tmp.path().join(".env");
|
||||
fs::write(
|
||||
|
|
@ -385,7 +386,7 @@ mod tests {
|
|||
test_security(AutonomyLevel::Full, 100),
|
||||
tmp.path().to_path_buf(),
|
||||
);
|
||||
let result = tool.get_credentials();
|
||||
let result = tool.get_credentials().await;
|
||||
|
||||
assert!(result.is_ok());
|
||||
let (token, user_key) = result.unwrap();
|
||||
|
|
|
|||
|
|
@ -368,14 +368,14 @@ mod tests {
|
|||
use crate::security::AutonomyLevel;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn test_setup() -> (TempDir, Config, Arc<SecurityPolicy>) {
|
||||
async fn test_setup() -> (TempDir, Config, Arc<SecurityPolicy>) {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let config = Config {
|
||||
workspace_dir: tmp.path().join("workspace"),
|
||||
config_path: tmp.path().join("config.toml"),
|
||||
..Config::default()
|
||||
};
|
||||
std::fs::create_dir_all(&config.workspace_dir).unwrap();
|
||||
tokio::fs::create_dir_all(&config.workspace_dir).await.unwrap();
|
||||
let security = Arc::new(SecurityPolicy::from_config(
|
||||
&config.autonomy,
|
||||
&config.workspace_dir,
|
||||
|
|
@ -383,9 +383,9 @@ mod tests {
|
|||
(tmp, config, security)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tool_name_and_schema() {
|
||||
let (_tmp, config, security) = test_setup();
|
||||
#[tokio::test]
|
||||
async fn tool_name_and_schema() {
|
||||
let (_tmp, config, security) = test_setup().await;
|
||||
let tool = ScheduleTool::new(security, config);
|
||||
assert_eq!(tool.name(), "schedule");
|
||||
let schema = tool.parameters_schema();
|
||||
|
|
@ -394,7 +394,7 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn list_empty() {
|
||||
let (_tmp, config, security) = test_setup();
|
||||
let (_tmp, config, security) = test_setup().await;
|
||||
let tool = ScheduleTool::new(security, config);
|
||||
|
||||
let result = tool.execute(json!({"action": "list"})).await.unwrap();
|
||||
|
|
@ -404,7 +404,7 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn create_get_and_cancel_roundtrip() {
|
||||
let (_tmp, config, security) = test_setup();
|
||||
let (_tmp, config, security) = test_setup().await;
|
||||
let tool = ScheduleTool::new(security, config);
|
||||
|
||||
let create = tool
|
||||
|
|
@ -440,7 +440,7 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn once_and_pause_resume_aliases_work() {
|
||||
let (_tmp, config, security) = test_setup();
|
||||
let (_tmp, config, security) = test_setup().await;
|
||||
let tool = ScheduleTool::new(security, config);
|
||||
|
||||
let once = tool
|
||||
|
|
@ -489,7 +489,7 @@ mod tests {
|
|||
},
|
||||
..Config::default()
|
||||
};
|
||||
std::fs::create_dir_all(&config.workspace_dir).unwrap();
|
||||
tokio::fs::create_dir_all(&config.workspace_dir).await.unwrap();
|
||||
let security = Arc::new(SecurityPolicy::from_config(
|
||||
&config.autonomy,
|
||||
&config.workspace_dir,
|
||||
|
|
@ -514,7 +514,7 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn unknown_action_returns_failure() {
|
||||
let (_tmp, config, security) = test_setup();
|
||||
let (_tmp, config, security) = test_setup().await;
|
||||
let tool = ScheduleTool::new(security, config);
|
||||
|
||||
let result = tool.execute(json!({"action": "explode"})).await.unwrap();
|
||||
|
|
|
|||
|
|
@ -363,7 +363,7 @@ mod tests {
|
|||
.unwrap();
|
||||
assert!(allowed.success);
|
||||
|
||||
let _ = std::fs::remove_file(std::env::temp_dir().join("zeroclaw_shell_approval_test"));
|
||||
let _ = tokio::fs::remove_file(std::env::temp_dir().join("zeroclaw_shell_approval_test")).await;
|
||||
}
|
||||
|
||||
// ── §5.2 Shell timeout enforcement tests ─────────────────
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue