use std::path::{Path, PathBuf}; use chrono::Duration; use sgclaw::compat::config_adapter::build_zeroclaw_config_from_settings; use sgclaw::config::DeepSeekSettings; use zeroclaw::cron::Schedule; fn workspace_root(label: &str) -> PathBuf { let root = std::env::temp_dir().join(format!("{label}-{}", uuid::Uuid::new_v4())); std::fs::create_dir_all(&root).unwrap(); root } #[tokio::test] async fn compat_cron_adapter_creates_lists_and_runs_due_agent_jobs() { let settings = DeepSeekSettings { api_key: "key".to_string(), base_url: "https://api.deepseek.com".to_string(), model: "deepseek-chat".to_string(), }; let workspace_root = workspace_root("sgclaw-cron"); let config = build_zeroclaw_config_from_settings(Path::new(&workspace_root), &settings); assert!(config.cron.enabled); assert!(!config.cron.catch_up_on_startup); assert!(!config.scheduler.enabled); let created = sgclaw::compat::cron_adapter::add_agent_job( &config, Some("search-weather".to_string()), Schedule::Every { every_ms: 1 }, "打开百度搜索天气", Some(vec!["browser_action".to_string()]), ) .unwrap(); let listed = sgclaw::compat::cron_adapter::list_jobs(&config).unwrap(); assert_eq!(listed.len(), 1); assert_eq!(listed[0].id, created.id); assert_eq!(listed[0].prompt.as_deref(), Some("打开百度搜索天气")); let results = sgclaw::compat::cron_adapter::run_due_jobs( &config, created.next_run + Duration::milliseconds(1), |job| { let output = format!("ran {}", job.prompt.as_deref().unwrap_or_default()); async move { Ok::(output) } }, ) .await .unwrap(); let runs = sgclaw::compat::cron_adapter::list_runs(&config, &created.id, 10).unwrap(); let updated = sgclaw::compat::cron_adapter::list_jobs(&config).unwrap(); assert_eq!(results.len(), 1); assert!(results[0].success); assert_eq!(results[0].job_id, created.id); assert_eq!(runs.len(), 1); assert_eq!(runs[0].status, "ok"); assert!(updated[0].last_status.as_deref() == Some("ok")); assert!(updated[0].next_run > created.next_run); }