blob: 13c0d8c4e1aa9670721bf5454d3ff46e9601077c [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Verify sirenia-rpc_macros works for the intended use case.
extern crate sirenia_rpc_macros;
use std::thread::spawn;
use anyhow::anyhow;
use assert_matches::assert_matches;
use libsirenia::rpc::RpcDispatcher;
use libsirenia::transport::create_transport_from_pipes;
use sirenia_rpc_macros::sirenia_rpc;
#[sirenia_rpc]
pub trait TestRpc<E> {
fn checked_neg(&mut self, input: i32) -> Result<Option<i32>, E>;
fn checked_add(&mut self, addend_a: i32, addend_b: i32) -> Result<Option<i32>, E>;
}
#[sirenia_rpc]
pub trait OtherRpc<E> {
fn checked_neg(&mut self, input: i64) -> Result<Option<i64>, E>;
fn checked_add(&mut self, addend_a: i64, addend_b: i64) -> Result<Option<i64>, E>;
}
#[sirenia_rpc]
pub trait NestedRpc<E>: TestRpc<E> + OtherRpc<E> {
fn terminate(&mut self) -> Result<(), E>;
fn echo_bytes(&mut self, bytes: Vec<u8>) -> Result<Vec<u8>, E>;
}
#[derive(Clone)]
struct NestedRpcServerImpl {}
impl TestRpc<anyhow::Error> for NestedRpcServerImpl {
fn checked_neg(&mut self, input: i32) -> Result<Option<i32>, anyhow::Error> {
Ok(input.checked_neg())
}
fn checked_add(&mut self, addend_a: i32, addend_b: i32) -> Result<Option<i32>, anyhow::Error> {
Ok(addend_a.checked_add(addend_b))
}
}
impl OtherRpc<anyhow::Error> for NestedRpcServerImpl {
fn checked_neg(&mut self, input: i64) -> Result<Option<i64>, anyhow::Error> {
Ok(input.checked_neg())
}
fn checked_add(&mut self, addend_a: i64, addend_b: i64) -> Result<Option<i64>, anyhow::Error> {
Ok(addend_a.checked_add(addend_b))
}
}
impl NestedRpc<anyhow::Error> for NestedRpcServerImpl {
fn terminate(&mut self) -> Result<(), anyhow::Error> {
Err(anyhow!("Done"))
}
fn echo_bytes(&mut self, bytes: Vec<u8>) -> Result<Vec<u8>, anyhow::Error> {
Ok(bytes)
}
}
#[test]
fn nested_rpc_test() {
let (server_transport, client_transport) = create_transport_from_pipes().unwrap();
let handler: Box<dyn NestedRpcServer> = Box::new(NestedRpcServerImpl {});
let mut dispatcher = RpcDispatcher::new_nonblocking(handler, server_transport).unwrap();
// Queue the client RPC:
let client_thread = spawn(move || {
let mut rpc_client = NestedRpcClient::new(client_transport);
let neg_resp = TestRpc::<anyhow::Error>::checked_neg(&mut rpc_client, 125).unwrap();
assert_matches!(neg_resp, Some(-125));
let add_resp = OtherRpc::<anyhow::Error>::checked_add(&mut rpc_client, 5, 4).unwrap();
assert_matches!(add_resp, Some(9));
assert!(rpc_client.terminate().is_err());
});
let sleep_for = None;
assert_matches!(dispatcher.read_complete_message(sleep_for), Ok(None));
assert_matches!(dispatcher.read_complete_message(sleep_for), Ok(None));
assert_matches!(dispatcher.read_complete_message(sleep_for), Ok(Some(_)));
// Explicitly call drop to close the pipe so the client thread gets the hang up since the return
// value should be a RemoveFd mutator.
drop(dispatcher);
client_thread.join().unwrap();
}