motorcortex-rust 0.5.0

Motorcortex Rust: a Rust client for the Motorcortex Core real-time control system (async + blocking).
Documentation
//! `request_parameter_tree` populates the client-side cache.

use motorcortex_rust::core::Request;
use motorcortex_rust::{ConnectionOptions, StatusCode};

use crate::{CERT_PATH, URL_REQ};

#[tokio::test]
async fn test_async_request_parameter_tree_populates_cache() {
    let req = Request::new();
    let opts = ConnectionOptions::new(CERT_PATH.to_string(), 5000, 5000);
    req.connect(URL_REQ, opts).await.expect("connect");

    // Cache starts empty.
    {
        let tree = req.parameter_tree();
        let guard = tree.read().unwrap();
        assert!(
            guard.get_parameter_info("root/Control/dummyDouble").is_none(),
            "fresh cache must not know server parameters",
        );
    }

    let status = req
        .request_parameter_tree()
        .await
        .expect("tree RPC completes");
    assert_eq!(status, StatusCode::Ok);

    // Cache now has at least the dummyDouble parameter the test_server
    // exposes — pin a known path to confirm the driver actually
    // wrote into the shared Arc.
    {
        let tree = req.parameter_tree();
        let guard = tree.read().unwrap();
        assert!(
            guard.get_parameter_info("root/Control/dummyDouble").is_some(),
            "tree cache should contain root/Control/dummyDouble after refresh",
        );
        // Data type field is populated too.
        assert!(
            guard
                .get_parameter_data_type("root/Control/dummyDouble")
                .is_some()
        );
    }

    req.disconnect().await.expect("disconnect");
}

#[tokio::test]
async fn test_async_get_parameter_tree_hash_returns_nonzero() {
    // A populated server tree must hash to something non-zero.
    // Also exercises the right reply decode (ParameterTreeHashMsg,
    // not ParameterTreeMsg — legacy bug fixed in 1f87dd5).
    let req = Request::new();
    let opts = ConnectionOptions::new(CERT_PATH.to_string(), 5000, 5000);
    req.connect(URL_REQ, opts).await.expect("connect");

    let hash = req
        .get_parameter_tree_hash()
        .await
        .expect("hash RPC completes");
    assert_ne!(hash, 0, "expected non-zero hash for a populated tree");

    req.disconnect().await.expect("disconnect");
}

#[tokio::test]
async fn test_async_connect_to_convenience_constructor() {
    // Request::connect_to = new() + connect() in one — exercise it.
    let opts = ConnectionOptions::new(CERT_PATH.to_string(), 5000, 5000);
    let req = Request::connect_to(URL_REQ, opts)
        .await
        .expect("connect_to must succeed against the test server");
    // The resulting handle should be usable for an RPC.
    req.request_parameter_tree().await.expect("tree");
    req.disconnect().await.expect("disconnect");
}

#[tokio::test]
async fn test_async_tree_cache_visible_on_cloned_handle() {
    // Populate via the original handle, read via a clone — the
    // Arc<RwLock<ParameterTree>> is shared, so the clone sees it too.
    let req = Request::new();
    let opts = ConnectionOptions::new(CERT_PATH.to_string(), 5000, 5000);
    req.connect(URL_REQ, opts).await.expect("connect");
    req.request_parameter_tree().await.expect("tree");

    let clone = req.clone();
    let tree = clone.parameter_tree();
    // Scope the guard so it drops before the next `.await` — clippy
    // rightly flags holding a sync lock across await points.
    {
        let guard = tree.read().unwrap();
        assert!(guard.get_parameter_info("root/Control/dummyDouble").is_some());
    }

    req.disconnect().await.expect("disconnect");
}