Unit test that tests execution of IPC calls without actually creating a separate process. This test is primarily intended to verify behavior of type conversion code that converts C++ objects to Cap'n Proto messages and vice versa. The test creates a thread which creates a FooImplementation object (defined in ipc_test.h) and a two-way pipe accepting IPC requests which call methods on the object th
| 58 | //! in ipc_test.h) and a two-way pipe accepting IPC requests which call methods |
| 59 | //! on the object through FooInterface (defined in ipc_test.capnp). |
| 60 | void IpcPipeTest() |
| 61 | { |
| 62 | // Setup: create FooImplementation object and listen for FooInterface requests |
| 63 | std::promise<std::unique_ptr<mp::ProxyClient<gen::FooInterface>>> foo_promise; |
| 64 | std::thread thread([&]() { |
| 65 | mp::EventLoop loop("IpcPipeTest", [](bool raise, const std::string& log) { LogInfo("LOG%i: %s", raise, log); }); |
| 66 | auto pipe = loop.m_io_context.provider->newTwoWayPipe(); |
| 67 | |
| 68 | auto connection_client = std::make_unique<mp::Connection>(loop, kj::mv(pipe.ends[0])); |
| 69 | auto foo_client = std::make_unique<mp::ProxyClient<gen::FooInterface>>( |
| 70 | connection_client->m_rpc_system->bootstrap(mp::ServerVatId().vat_id).castAs<gen::FooInterface>(), |
| 71 | connection_client.get(), /* destroy_connection= */ true); |
| 72 | (void)connection_client.release(); |
| 73 | foo_promise.set_value(std::move(foo_client)); |
| 74 | |
| 75 | auto connection_server = std::make_unique<mp::Connection>(loop, kj::mv(pipe.ends[1]), [&](mp::Connection& connection) { |
| 76 | auto foo_server = kj::heap<mp::ProxyServer<gen::FooInterface>>(std::make_shared<FooImplementation>(), connection); |
| 77 | return capnp::Capability::Client(kj::mv(foo_server)); |
| 78 | }); |
| 79 | connection_server->onDisconnect([&] { connection_server.reset(); }); |
| 80 | loop.loop(); |
| 81 | }); |
| 82 | std::unique_ptr<mp::ProxyClient<gen::FooInterface>> foo{foo_promise.get_future().get()}; |
| 83 | |
| 84 | // Test: make sure arguments were sent and return value is received |
| 85 | BOOST_CHECK_EQUAL(foo->add(1, 2), 3); |
| 86 | |
| 87 | COutPoint txout1{Txid::FromUint256(uint256{100}), 200}; |
| 88 | COutPoint txout2{foo->passOutPoint(txout1)}; |
| 89 | BOOST_CHECK(txout1 == txout2); |
| 90 | |
| 91 | UniValue uni1{UniValue::VOBJ}; |
| 92 | uni1.pushKV("i", 1); |
| 93 | uni1.pushKV("s", "two"); |
| 94 | UniValue uni2{foo->passUniValue(uni1)}; |
| 95 | BOOST_CHECK_EQUAL(uni1.write(), uni2.write()); |
| 96 | |
| 97 | CMutableTransaction mtx; |
| 98 | mtx.version = 2; |
| 99 | mtx.nLockTime = 3; |
| 100 | mtx.vin.emplace_back(txout1); |
| 101 | mtx.vout.emplace_back(COIN, CScript()); |
| 102 | CTransactionRef tx1{MakeTransactionRef(mtx)}; |
| 103 | CTransactionRef tx2{foo->passTransaction(tx1)}; |
| 104 | BOOST_CHECK(*Assert(tx1) == *Assert(tx2)); |
| 105 | |
| 106 | std::vector<char> vec1{'H', 'e', 'l', 'l', 'o'}; |
| 107 | std::vector<char> vec2{foo->passVectorChar(vec1)}; |
| 108 | BOOST_CHECK_EQUAL(std::string_view(vec1.begin(), vec1.end()), std::string_view(vec2.begin(), vec2.end())); |
| 109 | |
| 110 | auto script1{CScript() << OP_11}; |
| 111 | auto script2{foo->passScript(script1)}; |
| 112 | BOOST_CHECK_EQUAL(HexStr(script1), HexStr(script2)); |
| 113 | |
| 114 | // Test cleanup: disconnect and join thread |
| 115 | foo.reset(); |
| 116 | thread.join(); |
| 117 | } |
no test coverage detected