~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/asyncai

0
0
main
58 lines · 1.9 KB Raw History
use std::time::Duration;

use asyncai::mcp::{McpToolExecutor, StdioServerConfig};
use asyncai::resources::{EventExtractor, ResourceSource, WatchSignal};
use asyncai::ToolExecutor;
use serde_json::json;

const WAIT: Duration = Duration::from_secs(20);

async fn simple(args: &[&str]) -> McpToolExecutor {
    McpToolExecutor::connect_stdio(vec![StdioServerConfig {
        command: env!("CARGO_BIN_EXE_asyncai-mcp-simple").to_string(),
        args: args.iter().map(|arg| arg.to_string()).collect(),
    }])
    .await
    .unwrap()
}

#[tokio::test]
async fn watches_a_state_resource_with_subscriptions_listen() {
    let executor = simple(&[]).await;

    let resources = executor.list_resources().await.unwrap();
    assert_eq!(resources[0].uri, "memo://notes");
    assert!(!resources[0].template);
    assert!(
        resources[0].example.is_some(),
        "memo description has an Example: line"
    );
    assert!(resources[0].subscribable);

    let mut watch = executor.watch("memo://notes").await.unwrap();
    let baseline = executor.read_resource("memo://notes").await.unwrap();
    let mut extractor = EventExtractor::baseline(&baseline, 100);

    executor
        .call_tool("memo_set", json!({"key": "todo", "value": "ship"}))
        .await
        .unwrap();
    let signal = tokio::time::timeout(WAIT, watch.signals.recv())
        .await
        .expect("no update notification")
        .unwrap();
    assert_eq!(signal, WatchSignal::Updated);

    let events = extractor.extract(&executor.read_resource("memo://notes").await.unwrap());
    assert_eq!(
        events,
        vec![json!({"type": "ADDED", "key": "todo", "new": "ship", "old": null})]
    );
}

#[tokio::test]
async fn unknown_resources_are_errors() {
    let executor = simple(&[]).await;
    let error = executor.read_resource("memo://nope").await.unwrap_err();
    assert!(error.to_string().contains("memo://nope"), "{error}");
}