#include #include "../c++/remote_loopback.hpp" namespace { namespace sch { using namespace saw::schema; using TestInterface = Interface< Member, "foo"> >; } SAW_TEST("Remote Loopback RPC"){ using namespace saw; event_loop loop; wait_scope wait{loop}; remote rmt; auto eov = rmt.parse_address(0u); SAW_EXPECT(eov.is_value(), "Didn't parse correctly"); auto& addr = eov.get_value(); auto eo_u32_srv = rmt.template data_listen(*addr); SAW_EXPECT(eo_u32_srv.is_value(), std::string{"Couldn't listen: "} + std::string{eo_u32_srv.get_error().get_category()}); auto& u32_srv = eo_u32_srv.get_value(); auto eo_i64_srv = rmt.template data_listen(*addr); SAW_EXPECT(eo_i64_srv.is_value(), std::string{"Couldn't listen: "} + std::string{eo_i64_srv.get_error().get_category()}); auto& i64_srv = eo_i64_srv.get_value(); auto foo_func = [](data input) -> error_or> { data rv; rv.set(input.get() * 2); return rv; }; auto iface = interface_factory::create(std::move(foo_func)); auto eo_rpc_srv = rmt.template rpc_listen(*addr, std::move(iface)); SAW_EXPECT(eo_rpc_srv.is_value(), std::string{"Couldn't listen: "} + std::string{eo_rpc_srv.get_error().get_category()}); auto& rpc_srv = eo_rpc_srv.get_value(); id id32{0u}; id id64{0u}; data inp{21}; { auto eo_send = u32_srv->send(inp, id32); SAW_EXPECT(eo_send.is_value(), "Failed send."); } { auto eo_called = rpc_srv->template call<"foo">(id32, id64); SAW_EXPECT(eo_called.is_value(), (std::string{"Failed call: "} + std::string{eo_called.get_error().get_category()} )); } { auto eo_recv = i64_srv->receive(id64); SAW_EXPECT(eo_recv.is_value(), "Failed receive."); auto& recv = eo_recv.get_value(); SAW_EXPECT((recv.get() == 42), (std::string{"Wrong value received: "} + std::to_string(recv.get()))); } } SAW_TEST("Remote Loopback RPC Runtime Dispatch"){ using namespace saw; event_loop loop; wait_scope wait{loop}; remote rmt; auto eov = rmt.parse_address(0u); SAW_EXPECT(eov.is_value(), "Didn't parse correctly"); auto& addr = eov.get_value(); auto eo_u32_srv = rmt.template data_listen(*addr); SAW_EXPECT(eo_u32_srv.is_value(), std::string{"Couldn't listen: "} + std::string{eo_u32_srv.get_error().get_category()}); auto& u32_srv = eo_u32_srv.get_value(); auto eo_i64_srv = rmt.template data_listen(*addr); SAW_EXPECT(eo_i64_srv.is_value(), std::string{"Couldn't listen: "} + std::string{eo_i64_srv.get_error().get_category()}); auto& i64_srv = eo_i64_srv.get_value(); auto foo_func = [](data input) -> error_or> { data rv; rv.set(input.get() * 2); return rv; }; auto iface = interface_factory::create(std::move(foo_func)); auto eo_rpc_srv = rmt.template rpc_listen(*addr, std::move(iface)); SAW_EXPECT(eo_rpc_srv.is_value(), std::string{"Couldn't listen: "} + std::string{eo_rpc_srv.get_error().get_category()}); auto& rpc_srv = eo_rpc_srv.get_value(); id id32{0u}; /** * Deliberately not 0, since the server picks that one for the first * response below. */ id id64{7u}; data inp{21}; { auto eo_send = u32_srv->send(inp, id32); SAW_EXPECT(eo_send.is_value(), "Failed send."); } /** * This is the path a backend takes which transports the call itself. * Only the function id and the raw parameter id are known. The id the * server picked for the response is meant to travel back in the reply. */ { auto eo_called = rpc_srv->call_by_id(rpc_function_id<"foo">::value, id32.get_value()); SAW_EXPECT(eo_called.is_value(), (std::string{"Failed call: "} + std::string{eo_called.get_error().get_category()})); id resp_id{eo_called.get_value()}; auto eo_recv = i64_srv->receive(resp_id); SAW_EXPECT(eo_recv.is_value(), "Failed receive."); auto& recv = eo_recv.get_value(); SAW_EXPECT((recv.get() == 42), (std::string{"Wrong value received: "} + std::to_string(recv.get()))); } /** * Calling into a slot the caller picked beforehand. */ { auto eo_called = rpc_srv->call_by_id(rpc_function_id<"foo">::value, id32.get_value(), id64.get_value()); SAW_EXPECT(eo_called.is_value(), (std::string{"Failed call: "} + std::string{eo_called.get_error().get_category()})); auto eo_recv = i64_srv->receive(id64); SAW_EXPECT(eo_recv.is_value(), "Failed receive."); auto& recv = eo_recv.get_value(); SAW_EXPECT((recv.get() == 42), (std::string{"Wrong value received: "} + std::to_string(recv.get()))); } { auto eo_called = rpc_srv->call_by_id(rpc_function_id<"foo">::value + 1u, id32.get_value()); SAW_EXPECT(eo_called.is_error(), "An unknown function id should not be callable."); } } SAW_TEST("Remote Loopback RPC Client"){ using namespace saw; event_loop loop; wait_scope wait{loop}; remote rmt; auto eov = rmt.parse_address(0u); SAW_EXPECT(eov.is_value(), "Didn't parse correctly"); auto& addr = eov.get_value(); auto eo_u32_srv = rmt.template data_listen(*addr); SAW_EXPECT(eo_u32_srv.is_value(), std::string{"Couldn't listen: "} + std::string{eo_u32_srv.get_error().get_category()}); auto eo_i64_srv = rmt.template data_listen(*addr); SAW_EXPECT(eo_i64_srv.is_value(), std::string{"Couldn't listen: "} + std::string{eo_i64_srv.get_error().get_category()}); auto foo_func = [](data input) -> error_or> { data rv; rv.set(input.get() * 2); return rv; }; auto iface = interface_factory::create(std::move(foo_func)); auto eo_rpc_srv = rmt.template rpc_listen(*addr, std::move(iface)); SAW_EXPECT(eo_rpc_srv.is_value(), std::string{"Couldn't listen: "} + std::string{eo_rpc_srv.get_error().get_category()}); auto cvr_client = rmt.template rpc_connect(*addr); auto eo_client = cvr_client.take(); SAW_EXPECT(eo_client.is_value(), "Couldn't connect."); auto& client = eo_client.get_value(); data inp{21}; auto cvr_rmt_dat = client.template call<"foo">(std::move(inp)); auto eo_rmt_dat = cvr_rmt_dat.take(); SAW_EXPECT(eo_rmt_dat.is_value(), (std::string{"Failed call: "} + std::string{eo_rmt_dat.get_error().get_category()})); auto& rmt_dat = eo_rmt_dat.get_value(); auto eo_resp = rmt_dat.wait(wait); SAW_EXPECT(eo_resp.is_value(), "Failed receive."); SAW_EXPECT((eo_resp.get_value().get() == 42), (std::string{"Wrong value received: "} + std::to_string(eo_resp.get_value().get()))); } SAW_TEST("Remote Loopback Data"){ using namespace saw; event_loop loop; wait_scope wait{loop}; remote rmt; using Schema = sch::Array; auto eov = rmt.parse_address(0u); SAW_EXPECT(eov.is_value(), "Didn't parse correctly"); auto& addr = eov.get_value(); auto eo_srv = rmt.template data_listen(*addr); SAW_EXPECT(eo_srv.is_value(), std::string{"Couldn't listen: "} + std::string{eo_srv.get_error().get_category()}); auto& srv = eo_srv.get_value(); auto cvr_client = rmt.template data_connect(*addr); auto eo_client = cvr_client.take(); SAW_EXPECT(eo_client.is_value(), "Couldn't connect."); auto& client = eo_client.get_value(); data foo{4}; for(uint64_t i = 0; i < foo.size().get(); ++i){ foo.at(i).set(i * 2.0); } id sent_id = [&](){ auto eov = client.send(foo); SAW_EXPECT(eov.is_value(), "Failed send."); return eov.get_value(); }(); { auto conv = client.receive(sent_id); auto eov = conv.take(); SAW_EXPECT(eov.is_value(), "Failed receive."); // SAW_EXPECT(eov.get_value() == foo, "Wrong received value."); } { auto eov = client.find(sent_id); SAW_EXPECT(eov.is_value(), "Failed find."); auto& f_val = eov.get_value(); // SAW_EXPECT(f_val.is_valid(), "Nullptr in find."); // SAW_EXPECT(*f_val == foo, "Wrong received value."); } { auto eov = client.erase(sent_id); SAW_EXPECT(eov.is_value(), "Failed erase."); } { auto conv = client.receive(sent_id); auto eov = conv.take(); SAW_EXPECT(!eov.is_value(), "Failed receive. Value should already be erased."); } id alloc_id = [&](){ auto eov = client.allocate(data>{{4}}); SAW_EXPECT(eov.is_value(), "Failed send."); return eov.get_value(); }(); { auto eov = client.find(alloc_id); SAW_EXPECT(eov.is_value(), "Failed find."); auto& f_val = eov.get_value(); // SAW_EXPECT(f_val.is_valid(), "Nullptr in find."); // f_val->set(5u); } { auto conv = client.receive(alloc_id); auto eov = conv.take(); SAW_EXPECT(eov.is_value(), "Failed receive."); SAW_EXPECT(eov.get_value().size().get() == 4u, "Wrong received value."); } } }