Skip to content

Commit 4aaee23

Browse files
committed
test: add ipc test to test multiprocess type conversion code
Add unit test to test IPC method calls and type conversion between bitcoin c++ types and capnproto messages. Right now there are custom type hooks in bitcoin IPC code, so the test is simple, but in upcoming commits, code will be added to convert bitcoin types to capnproto messages, and the test will be expanded.
1 parent fe4e83f commit 4aaee23

File tree

7 files changed

+142
-1
lines changed

7 files changed

+142
-1
lines changed

build_msvc/test_bitcoin/test_bitcoin.vcxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</PropertyGroup>
1111
<ItemGroup>
1212
<ClCompile Include="..\..\src\test\*_properties.cpp" />
13-
<ClCompile Include="..\..\src\test\*_tests.cpp" />
13+
<ClCompile Include="..\..\src\test\*_tests.cpp" Exclude="..\..\src\test\ipc_tests.cpp" />
1414
<ClCompile Include="..\..\src\test\gen\*_gen.cpp" />
1515
<ClCompile Include="..\..\src\test\main.cpp" />
1616
<ClCompile Include="..\..\src\test\util\*.cpp" />

src/Makefile.test.include

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,13 +216,49 @@ BITCOIN_TEST_SUITE += \
216216
wallet/test/init_test_fixture.h
217217
endif # ENABLE_WALLET
218218

219+
if BUILD_MULTIPROCESS
220+
# Add boost ipc_tests definition to BITCOIN_TESTS
221+
BITCOIN_TESTS += test/ipc_tests.cpp
222+
223+
# Build ipc_test code in a separate library so it can be compiled with custom
224+
# LIBMULTIPROCESS_CFLAGS without those flags affecting other tests
225+
LIBBITCOIN_IPC_TEST=libbitcoin_ipc_test.a
226+
EXTRA_LIBRARIES += $(LIBBITCOIN_IPC_TEST)
227+
libbitcoin_ipc_test_a_SOURCES = \
228+
test/ipc_test.cpp \
229+
test/ipc_test.h
230+
libbitcoin_ipc_test_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
231+
libbitcoin_ipc_test_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(LIBMULTIPROCESS_CFLAGS)
232+
233+
# Generate various .c++/.h files from the ipc_test.capnp file
234+
include $(MPGEN_PREFIX)/include/mpgen.mk
235+
EXTRA_DIST += test/ipc_test.capnp
236+
libbitcoin_ipc_test_mpgen_output = \
237+
test/ipc_test.capnp.c++ \
238+
test/ipc_test.capnp.h \
239+
test/ipc_test.capnp.proxy-client.c++ \
240+
test/ipc_test.capnp.proxy-server.c++ \
241+
test/ipc_test.capnp.proxy-types.c++ \
242+
test/ipc_test.capnp.proxy-types.h \
243+
test/ipc_test.capnp.proxy.h
244+
nodist_libbitcoin_ipc_test_a_SOURCES = $(libbitcoin_ipc_test_mpgen_output)
245+
CLEANFILES += $(libbitcoin_ipc_test_mpgen_output)
246+
endif
247+
248+
# Explicitly list dependencies on generated headers as described in
249+
# https://www.gnu.org/software/automake/manual/html_node/Built-Sources-Example.html#Recording-Dependencies-manually
250+
test/libbitcoin_ipc_test_a-ipc_test.$(OBJEXT): test/ipc_test.capnp.h
251+
219252
test_test_bitcoin_SOURCES = $(BITCOIN_TEST_SUITE) $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
220253
test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(TESTDEFS) $(BOOST_CPPFLAGS) $(EVENT_CFLAGS)
221254
test_test_bitcoin_LDADD = $(LIBTEST_UTIL)
222255
if ENABLE_WALLET
223256
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
224257
test_test_bitcoin_CPPFLAGS += $(BDB_CPPFLAGS)
225258
endif
259+
if BUILD_MULTIPROCESS
260+
test_test_bitcoin_LDADD += $(LIBBITCOIN_IPC_TEST) $(LIBMULTIPROCESS_LIBS)
261+
endif
226262

227263
test_test_bitcoin_LDADD += $(LIBBITCOIN_NODE) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \
228264
$(LIBLEVELDB) $(LIBMEMENV) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) $(MINISKETCH_LIBS)

src/test/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# capnp generated files
2+
*.capnp.*

src/test/ipc_test.capnp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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+
@0xd71b0fc8727fdf83;
6+
7+
using Cxx = import "/capnp/c++.capnp";
8+
$Cxx.namespace("gen");
9+
10+
using Proxy = import "/mp/proxy.capnp";
11+
$Proxy.include("test/ipc_test.h");
12+
13+
interface FooInterface $Proxy.wrap("FooImplementation") {
14+
add @0 (a :Int32, b :Int32) -> (result :Int32);
15+
}

src/test/ipc_test.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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 <mp/proxy-types.h>
6+
#include <logging.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+
// Test cleanup: disconnect pipe and join thread
55+
disconnect_client();
56+
thread.join();
57+
}

src/test/ipc_test.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
#ifndef BITCOIN_TEST_IPC_TEST_H
6+
#define BITCOIN_TEST_IPC_TEST_H
7+
8+
#include <primitives/transaction.h>
9+
10+
class FooImplementation
11+
{
12+
public:
13+
int add(int a, int b) { return a + b; }
14+
};
15+
16+
void IpcTest();
17+
18+
#endif // BITCOIN_TEST_IPC_TEST_H

src/test/ipc_tests.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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 <test/ipc_test.h>
6+
#include <boost/test/unit_test.hpp>
7+
8+
BOOST_AUTO_TEST_SUITE(ipc_tests)
9+
BOOST_AUTO_TEST_CASE(ipc_tests)
10+
{
11+
IpcTest();
12+
}
13+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)