rmux-server 0.10.0

Tokio daemon and request dispatcher for the RMUX terminal multiplexer.
Documentation
use super::*;

async fn active_pane_id(handler: &RequestHandler, session: &SessionName) -> rmux_proto::PaneId {
    let state = handler.state.lock().await;
    state
        .sessions
        .session(session)
        .and_then(|session| session.window_at(0))
        .and_then(|window| window.pane(window.active_pane_index()))
        .expect("active pane exists")
        .id()
}

async fn select_missing_adjacent(handler: &RequestHandler, session: &SessionName) -> Response {
    handler
        .handle(Request::SelectPaneAdjacent(SelectPaneAdjacentRequest {
            target: PaneTarget::with_window(session.clone(), 0, 0),
            direction: SelectPaneDirection::Right,
            preserve_zoom: false,
        }))
        .await
}

async fn select_active_stable_pane(
    handler: &RequestHandler,
    session: &SessionName,
    pane_id: rmux_proto::PaneId,
) -> Response {
    handler
        .handle(Request::PaneSelect(PaneSelectRequest {
            target: PaneTargetRef::by_id(session.clone(), pane_id),
            title: None,
        }))
        .await
}

#[tokio::test]
async fn unchanged_adjacent_and_stable_selects_do_not_resize_the_runtime() {
    let handler = RequestHandler::new();
    let session = session_name("selection-noop-runtime");
    create_session(&handler, session.as_str()).await;
    handler.wait_for_initial_panes_for_test().await;
    let pane_id = active_pane_id(&handler, &session).await;
    let resize_count_before = {
        let mut state = handler.state.lock().await;
        let resize_count = state.window_runtime_resize_count_for_test();
        state.fail_next_resize_for_test();
        resize_count
    };

    let adjacent = select_missing_adjacent(&handler, &session).await;
    assert!(matches!(adjacent, Response::SelectPane(_)), "{adjacent:?}");
    let stable = select_active_stable_pane(&handler, &session, pane_id).await;
    assert!(matches!(stable, Response::SelectPane(_)), "{stable:?}");
    assert_eq!(
        handler
            .state
            .lock()
            .await
            .window_runtime_resize_count_for_test(),
        resize_count_before,
        "unchanged selection paths must not resize their runtime"
    );
}

#[cfg(windows)]
#[test]
fn unchanged_adjacent_and_stable_selects_succeed_while_conpty_is_deferred() {
    let runtime = tokio::runtime::Builder::new_multi_thread()
        .worker_threads(2)
        .max_blocking_threads(1)
        .enable_all()
        .build()
        .expect("build isolated deferred-pane runtime");

    runtime.block_on(async {
        let (blocker_started_tx, blocker_started_rx) = tokio::sync::oneshot::channel();
        let (blocker_release_tx, blocker_release_rx) = std::sync::mpsc::channel();
        let blocker = tokio::task::spawn_blocking(move || {
            let _ = blocker_started_tx.send(());
            blocker_release_rx
                .recv()
                .expect("release deferred-pane blocking worker");
        });
        blocker_started_rx
            .await
            .expect("blocking worker reports that it is occupied");

        let handler = RequestHandler::new();
        let session = session_name("selection-noop-deferred");
        create_session(&handler, session.as_str()).await;
        let pane_id = active_pane_id(&handler, &session).await;
        let resize_count_before = {
            let state = handler.state.lock().await;
            assert!(state.pane_is_starting_in_window(&session, 0, 0));
            assert!(state.pane_pid_in_window(&session, 0, 0).is_err());
            state.window_runtime_resize_count_for_test()
        };

        let adjacent = tokio::time::timeout(
            Duration::from_secs(1),
            select_missing_adjacent(&handler, &session),
        )
        .await
        .expect("unchanged adjacent selection does not wait for ConPTY");
        assert!(matches!(adjacent, Response::SelectPane(_)), "{adjacent:?}");
        let stable = tokio::time::timeout(
            Duration::from_secs(1),
            select_active_stable_pane(&handler, &session, pane_id),
        )
        .await
        .expect("unchanged stable selection does not wait for ConPTY");
        assert!(matches!(stable, Response::SelectPane(_)), "{stable:?}");
        {
            let state = handler.state.lock().await;
            assert!(state.pane_is_starting_in_window(&session, 0, 0));
            assert!(state.pane_pid_in_window(&session, 0, 0).is_err());
            assert_eq!(
                state.window_runtime_resize_count_for_test(),
                resize_count_before
            );
        }

        blocker_release_tx
            .send(())
            .expect("release deferred-pane blocking worker");
        blocker.await.expect("blocking worker joins");
        handler
            .wait_for_pane_startup_to_finish_for_test(&PaneTarget::new(session, 0))
            .await;
    });
}