ipc_test.cpp
1 // Copyright (c) 2023 The Bitcoin Core developers 2 // Distributed under the MIT software license, see the accompanying 3 // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 5 #include <logging.h> 6 #include <mp/proxy-types.h> 7 #include <test/ipc_test.capnp.h> 8 #include <test/ipc_test.capnp.proxy.h> 9 #include <test/ipc_test.h> 10 11 #include <future> 12 #include <kj/common.h> 13 #include <kj/memory.h> 14 #include <kj/test.h> 15 16 #include <boost/test/unit_test.hpp> 17 18 //! Unit test that tests execution of IPC calls without actually creating a 19 //! separate process. This test is primarily intended to verify behavior of type 20 //! conversion code that converts C++ objects to Cap'n Proto messages and vice 21 //! versa. 22 //! 23 //! The test creates a thread which creates a FooImplementation object (defined 24 //! in ipc_test.h) and a two-way pipe accepting IPC requests which call methods 25 //! on the object through FooInterface (defined in ipc_test.capnp). 26 void IpcTest() 27 { 28 // Setup: create FooImplemention object and listen for FooInterface requests 29 std::promise<std::unique_ptr<mp::ProxyClient<gen::FooInterface>>> foo_promise; 30 std::function<void()> disconnect_client; 31 std::thread thread([&]() { 32 mp::EventLoop loop("IpcTest", [](bool raise, const std::string& log) { LogPrintf("LOG%i: %s\n", raise, log); }); 33 auto pipe = loop.m_io_context.provider->newTwoWayPipe(); 34 35 auto connection_client = std::make_unique<mp::Connection>(loop, kj::mv(pipe.ends[0])); 36 auto foo_client = std::make_unique<mp::ProxyClient<gen::FooInterface>>( 37 connection_client->m_rpc_system.bootstrap(mp::ServerVatId().vat_id).castAs<gen::FooInterface>(), 38 connection_client.get(), /* destroy_connection= */ false); 39 foo_promise.set_value(std::move(foo_client)); 40 disconnect_client = [&] { loop.sync([&] { connection_client.reset(); }); }; 41 42 auto connection_server = std::make_unique<mp::Connection>(loop, kj::mv(pipe.ends[1]), [&](mp::Connection& connection) { 43 auto foo_server = kj::heap<mp::ProxyServer<gen::FooInterface>>(std::make_shared<FooImplementation>(), connection); 44 return capnp::Capability::Client(kj::mv(foo_server)); 45 }); 46 connection_server->onDisconnect([&] { connection_server.reset(); }); 47 loop.loop(); 48 }); 49 std::unique_ptr<mp::ProxyClient<gen::FooInterface>> foo{foo_promise.get_future().get()}; 50 51 // Test: make sure arguments were sent and return value is received 52 BOOST_CHECK_EQUAL(foo->add(1, 2), 3); 53 54 COutPoint txout1{Txid::FromUint256(uint256{100}), 200}; 55 COutPoint txout2{foo->passOutPoint(txout1)}; 56 BOOST_CHECK(txout1 == txout2); 57 58 UniValue uni1{UniValue::VOBJ}; 59 uni1.pushKV("i", 1); 60 uni1.pushKV("s", "two"); 61 UniValue uni2{foo->passUniValue(uni1)}; 62 BOOST_CHECK_EQUAL(uni1.write(), uni2.write()); 63 64 // Test cleanup: disconnect pipe and join thread 65 disconnect_client(); 66 thread.join(); 67 }