aprender-orchestrate 0.31.2

Sovereign AI orchestration: autonomous agents, ML serving, code analysis, and transpilation pipelines
Documentation
use super::*;
use std::env;

fn test_tool() -> ComputeTool {
    ComputeTool::new(env::current_dir().expect("cwd").to_string_lossy().into())
}

#[test]
fn test_tool_metadata() {
    let tool = test_tool();
    assert_eq!(tool.name(), "compute");
    let def = tool.definition();
    assert_eq!(def.name, "compute");
    assert!(def.description.contains("parallel"));
}

#[test]
fn test_required_capability() {
    let tool = test_tool();
    assert_eq!(tool.required_capability(), Capability::Compute);
}

#[test]
fn test_default_timeout() {
    let tool = test_tool();
    assert_eq!(tool.timeout(), Duration::from_secs(300));
}

#[test]
fn test_custom_timeout() {
    let tool = test_tool().with_timeout(Duration::from_secs(60));
    assert_eq!(tool.timeout(), Duration::from_secs(60));
}

#[test]
fn test_max_concurrent() {
    let tool = test_tool().with_max_concurrent(8);
    assert_eq!(tool.max_concurrent, 8);
}

#[test]
fn test_truncate_output() {
    assert_eq!(ComputeTool::truncate_output("hello"), "hello");
    let long = "x".repeat(MAX_TASK_OUTPUT_BYTES + 100);
    assert!(ComputeTool::truncate_output(&long).contains("[output truncated"));
}

#[test]
fn test_schema_structure() {
    let def = test_tool().definition();
    assert_eq!(def.input_schema["type"], "object");
    assert!(def.input_schema["required"]
        .as_array()
        .expect("required")
        .iter()
        .any(|v| v == "action"));
}

#[tokio::test]
async fn test_run_single_command() {
    let tool = test_tool();
    let result = tool
        .execute(serde_json::json!({
            "action": "run",
            "command": "echo compute_test"
        }))
        .await;
    assert!(!result.is_error, "error: {}", result.content);
    assert!(result.content.contains("compute_test"));
}

#[tokio::test]
async fn test_run_failing_command() {
    let tool = test_tool();
    let result = tool
        .execute(serde_json::json!({
            "action": "run",
            "command": "false"
        }))
        .await;
    assert!(result.is_error);
    assert!(result.content.contains("exit code"));
}

#[tokio::test]
async fn test_parallel_commands() {
    let tool = test_tool();
    let result = tool
        .execute(serde_json::json!({
            "action": "parallel",
            "commands": ["echo task1", "echo task2"]
        }))
        .await;
    assert!(!result.is_error, "error: {}", result.content);
    assert!(result.content.contains("Task 1"));
    assert!(result.content.contains("Task 2"));
    assert!(result.content.contains("task1"));
    assert!(result.content.contains("task2"));
}

#[tokio::test]
async fn test_missing_action() {
    let tool = test_tool();
    let result = tool.execute(serde_json::json!({"command": "echo hi"})).await;
    assert!(result.is_error);
    assert!(result.content.contains("missing"));
}

#[tokio::test]
async fn test_missing_command() {
    let tool = test_tool();
    let result = tool.execute(serde_json::json!({"action": "run"})).await;
    assert!(result.is_error);
    assert!(result.content.contains("missing"));
}

#[tokio::test]
async fn test_empty_commands_array() {
    let tool = test_tool();
    let result = tool
        .execute(serde_json::json!({
            "action": "parallel",
            "commands": []
        }))
        .await;
    assert!(result.is_error);
    assert!(result.content.contains("empty"));
}

#[tokio::test]
async fn test_parallel_exceeds_max_concurrent() {
    let tool = test_tool().with_max_concurrent(2);
    let result = tool
        .execute(serde_json::json!({
            "action": "parallel",
            "commands": [
                "echo one",
                "echo two",
                "echo three",
                "echo four"
            ]
        }))
        .await;
    // Should only run 2 tasks (max_concurrent)
    assert!(!result.is_error, "error: {}", result.content);
    assert!(result.content.contains("Task 1"));
    assert!(result.content.contains("Task 2"));
    // Tasks 3 and 4 are dropped
    assert!(!result.content.contains("Task 3"));
}

#[tokio::test]
async fn test_run_command_with_stderr() {
    let tool = test_tool();
    let result = tool
        .execute(serde_json::json!({
            "action": "run",
            "command": "echo ok && echo warning >&2"
        }))
        .await;
    assert!(!result.is_error);
    assert!(result.content.contains("ok"));
    assert!(result.content.contains("warning"));
}

#[tokio::test]
async fn test_parallel_with_mixed_results() {
    let tool = test_tool();
    let result = tool
        .execute(serde_json::json!({
            "action": "parallel",
            "commands": ["echo success", "false"]
        }))
        .await;
    // One task fails — should be reported as error
    assert!(result.is_error);
    assert!(result.content.contains("Task 1"));
    assert!(result.content.contains("Task 2"));
}

#[tokio::test]
async fn test_parallel_missing_commands() {
    let tool = test_tool();
    let result = tool
        .execute(serde_json::json!({
            "action": "parallel"
        }))
        .await;
    assert!(result.is_error);
    assert!(result.content.contains("missing"));
}

#[tokio::test]
async fn test_unknown_action() {
    let tool = test_tool();
    let result = tool
        .execute(serde_json::json!({
            "action": "cancel"
        }))
        .await;
    assert!(result.is_error);
    assert!(result.content.contains("unknown action"));
}