use oxi_agent::prelude::*;
use std::sync::{Arc, Mutex};
#[tokio::test]
async fn test_read_tool_progress_streaming() {
use tokio::fs;
let test_content = "x".repeat(10000); let test_path = "/tmp/oxi_test_large_file.txt";
fs::write(test_path, &test_content).await.unwrap();
let progress_updates = Arc::new(Mutex::new(Vec::new()));
let progress_clone = progress_updates.clone();
let tool = ReadTool::new();
tool.on_progress(Arc::new(move |msg: String| {
progress_clone.lock().unwrap().push(msg);
}));
let params = serde_json::json!({ "path": test_path });
let result = tool
.execute("test_call_id", params, None, &ToolContext::default())
.await;
assert!(result.is_ok());
let result = result.unwrap();
assert!(result.success);
let updates = progress_updates.lock().unwrap();
assert!(
!updates.is_empty(),
"Expected progress updates for large file"
);
assert!(
updates.iter().any(|u| u.contains("Reading file")),
"Should have file start message"
);
let _ = fs::remove_file(test_path).await;
}
#[tokio::test]
async fn test_bash_tool_progress_streaming() {
let progress_updates = Arc::new(Mutex::new(Vec::new()));
let progress_clone = progress_updates.clone();
let tool = BashTool::new();
tool.on_progress(Arc::new(move |msg: String| {
progress_clone.lock().unwrap().push(msg);
}));
let params = serde_json::json!({
"command": "echo 'Hello World' && sleep 0.1 && echo 'Done'"
});
let result = tool
.execute("test_call_id", params, None, &ToolContext::default())
.await;
assert!(result.is_ok());
let result = result.unwrap();
assert!(result.success);
assert!(result.output.contains("Hello World"));
let updates = progress_updates.lock().unwrap();
assert!(
!updates.is_empty(),
"Expected progress updates for bash command"
);
assert!(
updates
.iter()
.any(|u| u.contains("Executing:") || u.contains("Running")),
"Should have execution message"
);
assert!(
updates.iter().any(|u| u.contains("exited with code")),
"Should have exit message"
);
}
#[tokio::test]
async fn test_tool_without_progress_callback() {
let tool = ReadTool::new();
let test_path = "/tmp/oxi_test_small_file.txt";
tokio::fs::write(test_path, "Hello, World!").await.unwrap();
let params = serde_json::json!({ "path": test_path });
let result = tool
.execute("test_call_id", params, None, &ToolContext::default())
.await;
assert!(result.is_ok());
let result = result.unwrap();
assert!(result.success);
assert!(result.output.contains("Hello, World!"));
let _ = tokio::fs::remove_file(test_path).await;
}
#[tokio::test]
async fn test_read_tool_small_file_no_progress() {
let test_path = "/tmp/oxi_test_tiny_file.txt";
tokio::fs::write(test_path, "Small content").await.unwrap();
let progress_updates = Arc::new(Mutex::new(Vec::new()));
let progress_clone = progress_updates.clone();
let tool = ReadTool::new();
tool.on_progress(Arc::new(move |msg: String| {
progress_clone.lock().unwrap().push(msg);
}));
let params = serde_json::json!({ "path": test_path });
let result = tool
.execute("test_call_id", params, None, &ToolContext::default())
.await;
assert!(result.is_ok());
let updates = progress_updates.lock().unwrap();
assert!(!updates.is_empty(), "Should have at least start message");
let _ = tokio::fs::remove_file(test_path).await;
}