Branch data Line data Source code
1 : : // Copyright (c) 2023-present 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 <interfaces/init.h>
6 : : #include <ipc/capnp/mining.capnp.h>
7 : : #include <ipc/capnp/protocol.h>
8 : : #include <interfaces/ipc.h>
9 : : #include <ipc/process.h>
10 : : #include <ipc/protocol.h>
11 : : #include <ipc/test/ipc_test.capnp.h>
12 : : #include <ipc/test/ipc_test.capnp.proxy.h>
13 : : #include <ipc/test/ipc_test.h>
14 : : #include <mp/proxy-types.h>
15 : : #include <ipc/types.h>
16 : :
17 : : #include <test/util/common.h>
18 : : #include <test/util/setup_common.h>
19 : : #include <tinyformat.h>
20 : : #include <util/log.h>
21 : : #include <validation.h>
22 : :
23 : : #include <future>
24 : : #include <optional>
25 : : #include <thread>
26 : : #include <kj/common.h>
27 : : #include <kj/memory.h>
28 : : #include <kj/test.h>
29 : : #include <stdexcept>
30 : :
31 : : #include <boost/test/unit_test.hpp>
32 : :
33 : : static_assert(ipc::capnp::messages::MAX_MONEY == MAX_MONEY);
34 : : static_assert(ipc::capnp::messages::MAX_DOUBLE == std::numeric_limits<double>::max());
35 : : static_assert(ipc::capnp::messages::DEFAULT_BLOCK_RESERVED_WEIGHT == DEFAULT_BLOCK_RESERVED_WEIGHT);
36 : : static_assert(ipc::capnp::messages::DEFAULT_COINBASE_OUTPUT_MAX_ADDITIONAL_SIGOPS == DEFAULT_COINBASE_OUTPUT_MAX_ADDITIONAL_SIGOPS);
37 : :
38 : : //! Remote init class.
39 : 3 : class TestInit : public interfaces::Init
40 : : {
41 : : public:
42 : 8 : std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
43 : : };
44 : :
45 : : //! Generate a temporary path with temp_directory_path and mkstemp
46 : 3 : static std::string TempPath(std::string_view pattern)
47 : : {
48 [ + - + - : 24 : std::string temp{fs::PathToString(fs::path{fs::temp_directory_path()} / fs::PathFromString(std::string{pattern}))};
+ - - + ]
49 [ + - ]: 3 : temp.push_back('\0');
50 [ + - ]: 3 : int fd{mkstemp(temp.data())};
51 [ + - + - ]: 3 : BOOST_CHECK_GE(fd, 0);
52 [ + - + - : 3 : BOOST_CHECK_EQUAL(close(fd), 0);
+ - ]
53 [ - + + - ]: 3 : temp.resize(temp.size() - 1);
54 [ + - + - ]: 3 : fs::remove(fs::PathFromString(temp));
55 : 3 : return temp;
56 : 0 : }
57 : :
58 : : //! Unit test that tests execution of IPC calls without actually creating a
59 : : //! separate process. This test is primarily intended to verify behavior of type
60 : : //! conversion code that converts C++ objects to Cap'n Proto messages and vice
61 : : //! versa.
62 : : //!
63 : : //! The test creates a thread which creates a FooImplementation object (defined
64 : : //! in ipc_test.h) and a two-way pipe accepting IPC requests which call methods
65 : : //! on the object through FooInterface (defined in ipc_test.capnp).
66 : 1 : void IpcPipeTest()
67 : : {
68 : : // Setup: create FooImplementation object and listen for FooInterface requests
69 : 1 : std::promise<std::unique_ptr<mp::ProxyClient<gen::FooInterface>>> foo_promise;
70 : 2 : std::thread thread([&]() {
71 [ + - ]: 68 : mp::EventLoop loop("IpcPipeTest", [](bool raise, const std::string& log) { LogInfo("LOG%i: %s", raise, log); });
72 [ + - ]: 1 : auto pipe = loop.m_io_context.provider->newTwoWayPipe();
73 : :
74 [ + - ]: 1 : auto connection_client = std::make_unique<mp::Connection>(loop, kj::mv(pipe.ends[0]));
75 : 1 : auto foo_client = std::make_unique<mp::ProxyClient<gen::FooInterface>>(
76 [ + - + - : 1 : connection_client->m_rpc_system->bootstrap(mp::ServerVatId().vat_id).castAs<gen::FooInterface>(),
+ - + - ]
77 [ + - + - ]: 2 : connection_client.get(), /* destroy_connection= */ true);
78 [ + - ]: 1 : (void)connection_client.release();
79 [ + - ]: 1 : foo_promise.set_value(std::move(foo_client));
80 : :
81 : 2 : auto connection_server = std::make_unique<mp::Connection>(loop, kj::mv(pipe.ends[1]), [&](mp::Connection& connection) {
82 [ + - ]: 1 : auto foo_server = kj::heap<mp::ProxyServer<gen::FooInterface>>(std::make_shared<FooImplementation>(), connection);
83 [ + - + - ]: 1 : return capnp::Capability::Client(kj::mv(foo_server));
84 [ + - ]: 2 : });
85 [ + - + - ]: 2 : connection_server->onDisconnect([&] { connection_server.reset(); });
86 [ + - ]: 1 : loop.loop();
87 [ + - + - ]: 2 : });
88 [ + - + - ]: 2 : std::unique_ptr<mp::ProxyClient<gen::FooInterface>> foo{foo_promise.get_future().get()};
89 : :
90 : : // Test: make sure arguments were sent and return value is received
91 [ + - + - : 1 : BOOST_CHECK_EQUAL(foo->add(1, 2), 3);
+ - ]
92 : :
93 [ + - ]: 1 : COutPoint txout1{Txid::FromUint256(uint256{100}), 200};
94 [ + - ]: 1 : COutPoint txout2{foo->passOutPoint(txout1)};
95 [ + - + - ]: 2 : BOOST_CHECK(txout1 == txout2);
96 : :
97 : 1 : UniValue uni1{UniValue::VOBJ};
98 [ + - + - : 2 : uni1.pushKV("i", 1);
+ - ]
99 [ + - + - : 2 : uni1.pushKV("s", "two");
+ - ]
100 [ + - + - ]: 1 : UniValue uni2{foo->passUniValue(uni1)};
101 [ + - + - : 1 : BOOST_CHECK_EQUAL(uni1.write(), uni2.write());
+ - + - ]
102 : :
103 [ + - ]: 1 : CMutableTransaction mtx;
104 : 1 : mtx.version = 2;
105 : 1 : mtx.nLockTime = 3;
106 [ + - ]: 1 : mtx.vin.emplace_back(txout1);
107 [ + - ]: 1 : mtx.vout.emplace_back(COIN, CScript());
108 [ + - ]: 1 : CTransactionRef tx1{MakeTransactionRef(mtx)};
109 [ + - + - ]: 2 : CTransactionRef tx2{foo->passTransaction(tx1)};
110 [ + - - + : 2 : BOOST_CHECK(Assert(tx1)->Equals(*Assert(tx2)));
- + + - +
- ]
111 : :
112 : 1 : std::vector<CTransactionRef> txs1;
113 [ + - ]: 1 : txs1.push_back(tx1);
114 [ + - - + ]: 1 : txs1.push_back(nullptr);
115 [ + - + - ]: 1 : std::vector<CTransactionRef> txs2(foo->passTransactions(txs1));
116 [ + - - + : 1 : BOOST_CHECK_EQUAL(txs2.size(), 2);
+ - ]
117 [ + - - + : 2 : BOOST_CHECK(Assert(txs1[0])->Equals(*Assert(txs2[0])));
- + + - +
- ]
118 [ + - + - : 2 : BOOST_CHECK(!txs2[1]);
+ - ]
119 : :
120 [ + - ]: 1 : std::vector<char> vec1{'H', 'e', 'l', 'l', 'o'};
121 [ + - + - ]: 1 : std::vector<char> vec2{foo->passVectorChar(vec1)};
122 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(std::string_view(vec1.begin(), vec1.end()), std::string_view(vec2.begin(), vec2.end()));
123 : :
124 [ + - ]: 1 : auto script1{CScript() << OP_11};
125 [ + - ]: 1 : auto script2{foo->passScript(script1)};
126 [ + - - + : 3 : BOOST_CHECK_EQUAL(HexStr(script1), HexStr(script2));
+ - + - +
- ]
127 : :
128 : : // Test cleanup: disconnect and join thread
129 [ + - ]: 1 : foo.reset();
130 [ + - ]: 1 : thread.join();
131 [ + - + - ]: 4 : }
132 : :
133 : : //! Test ipc::Protocol connect() and serve() methods connecting over a socketpair.
134 : 1 : void IpcSocketPairTest()
135 : : {
136 : 1 : std::unique_ptr<interfaces::Init> init{std::make_unique<TestInit>()};
137 [ + - ]: 1 : std::unique_ptr<ipc::Protocol> protocol{ipc::capnp::MakeCapnpProtocol("IpcSocketPairTest")};
138 : 1 : mp::Stream client_stream;
139 [ + - ]: 1 : std::promise<void> promise;
140 : 2 : std::thread thread([&]() {
141 [ + - ]: 1 : protocol->serve(*init, [&] {
142 : 1 : auto pair{mp::SocketPair()};
143 : 1 : client_stream = protocol->makeStream(pair[0]);
144 : 1 : promise.set_value();
145 : 1 : return protocol->makeStream(pair[1]);
146 : : });
147 [ + - ]: 2 : });
148 [ + - + - ]: 2 : promise.get_future().wait();
149 [ + - ]: 1 : std::unique_ptr<interfaces::Init> remote_init{protocol->connect(std::move(client_stream))};
150 [ + - ]: 1 : std::unique_ptr<interfaces::Echo> remote_echo{remote_init->makeEcho()};
151 [ + - + - : 1 : BOOST_CHECK_EQUAL(remote_echo->echo("echo test"), "echo test");
+ - + - ]
152 [ + - ]: 1 : remote_echo.reset();
153 [ + - ]: 1 : remote_init.reset();
154 [ + - ]: 1 : thread.join();
155 : 1 : }
156 : :
157 : : //! Test ipc::Process bind() and connect() methods connecting over a unix socket.
158 : 1 : void IpcSocketTest(const fs::path& datadir)
159 : : {
160 : 1 : std::unique_ptr<interfaces::Init> init{std::make_unique<TestInit>()};
161 [ + - ]: 1 : std::unique_ptr<ipc::Protocol> protocol{ipc::capnp::MakeCapnpProtocol("IpcSocketTest")};
162 [ + - ]: 1 : std::unique_ptr<ipc::Process> process{ipc::MakeProcess()};
163 : :
164 [ + - ]: 1 : std::string invalid_bind{"invalid:"};
165 [ + - + - : 3 : BOOST_CHECK_THROW(process->bind(datadir, "test_bitcoin", invalid_bind), std::invalid_argument);
- + - - -
- - + + -
+ - ]
166 [ + - + - : 3 : BOOST_CHECK_THROW(process->connect(datadir, "test_bitcoin", invalid_bind), std::invalid_argument);
- + - - -
- - + + -
+ - ]
167 : :
168 : 3 : auto bind_and_listen{[&](const std::string& bind_address) {
169 [ - + ]: 2 : std::string address{bind_address};
170 [ + - + - ]: 2 : mp::SocketId serve_fd = process->bind(datadir, "test_bitcoin", address);
171 [ + - + - ]: 2 : BOOST_CHECK_NE(serve_fd, mp::SocketError);
172 [ + - + - ]: 2 : BOOST_CHECK_EQUAL(address, bind_address);
173 [ + - ]: 2 : protocol->listen(serve_fd, *init);
174 : 2 : }};
175 : :
176 : 6 : auto connect_and_test{[&](const std::string& connect_address) {
177 [ - + ]: 5 : std::string address{connect_address};
178 [ + - + - ]: 5 : mp::SocketId connect_fd{process->connect(datadir, "test_bitcoin", address)};
179 [ + - + - ]: 5 : BOOST_CHECK_EQUAL(address, connect_address);
180 [ + - + - ]: 5 : std::unique_ptr<interfaces::Init> remote_init{protocol->connect(protocol->makeStream(connect_fd))};
181 [ + - ]: 5 : std::unique_ptr<interfaces::Echo> remote_echo{remote_init->makeEcho()};
182 [ + - + - : 5 : BOOST_CHECK_EQUAL(remote_echo->echo("echo test"), "echo test");
+ - + - ]
183 : 5 : }};
184 : :
185 : : // Need to specify explicit socket addresses outside the data directory, because the data
186 : : // directory path is so long that the default socket address and any other
187 : : // addresses in the data directory would fail with errors like:
188 : : // Address 'unix' path '"/tmp/test_common_Bitcoin Core/ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff/test_bitcoin.sock"' exceeded maximum socket path length
189 : 1 : std::vector<std::string> addresses{
190 [ + - ]: 1 : strprintf("unix:%s", TempPath("bitcoin_sock0_XXXXXX")),
191 [ + - ]: 2 : strprintf("unix:%s", TempPath("bitcoin_sock1_XXXXXX")),
192 [ - + + + : 3 : };
- - ]
193 : :
194 : : // Bind and listen on multiple addresses
195 [ + + ]: 3 : for (const auto& address : addresses) {
196 [ + - ]: 2 : bind_and_listen(address);
197 : : }
198 : :
199 : : // Connect and test each address multiple times.
200 [ + + ]: 6 : for (int i : {0, 1, 0, 0, 1}) {
201 [ + - ]: 5 : connect_and_test(addresses[i]);
202 : : }
203 [ + - + - : 3 : }
- - ]
204 : :
205 : : //! Test ipc::Protocol listen() local connection limiting over a unix socket.
206 : 1 : void IpcSocketMaxConnectionsTest(const fs::path& datadir)
207 : : {
208 : 1 : std::unique_ptr<interfaces::Init> init{std::make_unique<TestInit>()};
209 [ + - ]: 1 : std::unique_ptr<ipc::Protocol> protocol{ipc::capnp::MakeCapnpProtocol("IpcSocketMaxConnectionsTest")};
210 [ + - ]: 1 : std::unique_ptr<ipc::Process> process{ipc::MakeProcess()};
211 : :
212 [ + - + - ]: 1 : std::string address{strprintf("unix:%s", TempPath("bitcoin_sock_limit_XXXXXX"))};
213 [ + - + - ]: 1 : mp::SocketId serve_fd = process->bind(datadir, "test_bitcoin", address);
214 [ + - + - ]: 1 : BOOST_CHECK_NE(serve_fd, mp::SocketError);
215 [ + - ]: 1 : protocol->listen(serve_fd, *init, /*max_connections=*/1);
216 : :
217 : 2 : auto connect_fd{[&](const std::string& connect_address) {
218 [ - + ]: 1 : std::string addr{connect_address};
219 [ + - + - ]: 1 : mp::SocketId fd{process->connect(datadir, "test_bitcoin", addr)};
220 [ - + ]: 2 : return std::make_pair(fd, addr);
221 : 1 : }};
222 : :
223 [ + - + - ]: 1 : auto [fd1, addr1] = connect_fd(address);
224 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(addr1, address);
225 [ + - + - ]: 1 : std::unique_ptr<interfaces::Init> remote_init1{protocol->connect(protocol->makeStream(fd1))};
226 [ + - ]: 1 : std::unique_ptr<interfaces::Echo> remote_echo1{remote_init1->makeEcho()};
227 [ + - + - : 1 : BOOST_CHECK_EQUAL(remote_echo1->echo("echo test 1"), "echo test 1");
+ - + - ]
228 : :
229 : 2 : auto second_call = std::async(std::launch::async, [&] {
230 [ - + ]: 1 : std::string addr{address};
231 [ + - + - ]: 1 : mp::SocketId fd{process->connect(datadir, "test_bitcoin", addr)};
232 [ + - + - ]: 1 : std::unique_ptr<interfaces::Init> remote_init{protocol->connect(protocol->makeStream(fd))};
233 [ + - ]: 1 : std::unique_ptr<interfaces::Echo> remote_echo{remote_init->makeEcho()};
234 [ + - + - ]: 2 : return std::make_pair(remote_echo->echo("echo test 2"), addr);
235 [ + - ]: 2 : });
236 : :
237 [ + - + - : 2 : BOOST_CHECK(second_call.wait_for(std::chrono::milliseconds{100}) == std::future_status::timeout);
+ - + - ]
238 : :
239 [ + - ]: 1 : remote_echo1.reset();
240 [ + - ]: 1 : remote_init1.reset();
241 : :
242 [ + - + - : 2 : BOOST_REQUIRE(second_call.wait_for(std::chrono::seconds{5}) == std::future_status::ready);
+ - + - ]
243 [ + - + - ]: 1 : auto [echo2, addr2] = second_call.get();
244 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(addr2, address);
245 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(echo2, "echo test 2");
246 [ - + ]: 2 : }
247 : :
248 : : BOOST_FIXTURE_TEST_SUITE(ipc_tests, BasicTestingSetup)
249 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(ipc_tests)
+ - + - -
+ + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- ]
250 : : {
251 : 1 : IpcPipeTest();
252 : 1 : IpcSocketPairTest();
253 [ + - ]: 1 : IpcSocketTest(m_args.GetDataDirNet());
254 [ + - ]: 1 : IpcSocketMaxConnectionsTest(m_args.GetDataDirNet());
255 : 1 : }
256 : :
257 : : // Test address parsing.
258 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(parse_address_test)
+ - + - -
+ + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- ]
259 : : {
260 : 1 : std::unique_ptr<ipc::Process> process{ipc::MakeProcess()};
261 [ + - ]: 1 : fs::path datadir{"/var/empty/notexist"};
262 : 4 : auto check_notexist{[](const std::system_error& e) { return e.code() == std::errc::no_such_file_or_directory; }};
263 : 6 : auto check_address{[&](std::string address, std::string expect_address, std::string expect_error) {
264 [ + + ]: 5 : if (expect_error.empty()) {
265 [ + - + - : 9 : BOOST_CHECK_EXCEPTION(process->connect(datadir, "test_bitcoin", address), std::system_error, check_notexist);
- + - - -
- - + + -
+ - ]
266 : : } else {
267 [ + - + - : 6 : BOOST_CHECK_EXCEPTION(process->connect(datadir, "test_bitcoin", address), std::invalid_argument, HasReason(expect_error));
- + - - -
- - + + -
- + + - +
- ]
268 : : }
269 [ + - ]: 5 : BOOST_CHECK_EQUAL(address, expect_address);
270 : 6 : }};
271 [ + - + - : 4 : std::string prefix{fs::PathToString(datadir / "")};
- + ]
272 [ + - + - : 3 : check_address("unix", "unix:" + prefix + "test_bitcoin.sock", "");
+ - + - ]
273 [ + - + - : 3 : check_address("unix:", "unix:" + prefix + "test_bitcoin.sock", "");
+ - + - ]
274 [ + - + - : 3 : check_address("unix:path.sock", "unix:" + prefix + "path.sock", "");
+ - + - ]
275 [ + - ]: 2 : check_address("unix:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.sock",
276 [ + - ]: 2 : "unix:" + prefix + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.sock",
277 [ + - + - ]: 3 : "Unix address path \"" + prefix + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.sock\" exceeded maximum socket path length");
278 [ + - + - : 2 : check_address("invalid", "invalid", "Unrecognized address 'invalid'");
+ - + - ]
279 : :
280 : 22 : auto check_listen_address{[](const std::string& configured_address, const std::string& expected_address, size_t expected_max_connections, const std::string& expected_error = "") {
281 [ - + + - ]: 42 : auto listen_address{interfaces::Ipc::parseListenAddress(configured_address)};
282 [ + + ]: 21 : if (!expected_error.empty()) {
283 [ + - + - : 24 : BOOST_CHECK(!listen_address);
+ - ]
284 [ + - + - : 12 : BOOST_CHECK_EQUAL(util::ErrorString(listen_address).original, expected_error);
+ - ]
285 : 12 : return;
286 : : }
287 [ + - + - : 18 : BOOST_REQUIRE(listen_address);
+ - ]
288 [ + - + - ]: 9 : BOOST_CHECK_EQUAL(listen_address->address, expected_address);
289 [ + - + - ]: 9 : BOOST_CHECK_EQUAL(listen_address->max_connections, expected_max_connections);
290 : 21 : }};
291 [ + - + - : 2 : check_listen_address("unix", "unix", ipc::DEFAULT_MAX_CONNECTIONS);
+ - + - ]
292 [ + - + - : 2 : check_listen_address("unix:", "unix:", ipc::DEFAULT_MAX_CONNECTIONS);
+ - + - ]
293 [ + - + - : 2 : check_listen_address("unix:,max-connections=8", "unix:", 8);
+ - + - ]
294 [ + - + - : 2 : check_listen_address("unix:path.sock,max-connections=8", "unix:path.sock", 8);
+ - + - ]
295 [ + - + - : 2 : check_listen_address("unix:,max-connections=1", "unix:", 1);
+ - + - ]
296 [ + - + - : 2 : check_listen_address("unix:,max-connections=256", "unix:", ipc::MAX_CONNECTIONS);
+ - + - ]
297 [ + - + - : 2 : check_listen_address("unix:path.sock,max-connections=8,unknown=1", "", 0, "Unknown socket option 'unknown'");
+ - + - ]
298 [ + - + - : 2 : check_listen_address("unix:,max-connections=8,", "", 0, "Empty socket option");
+ - + - ]
299 [ + - + - : 2 : check_listen_address("unix:,,max-connections=8", "", 0, "Empty socket option");
+ - + - ]
300 [ + - + - : 2 : check_listen_address("unix:,max-connections=8,,max-connections=8", "", 0, "Empty socket option");
+ - + - ]
301 [ + - + - : 2 : check_listen_address("unix:,max-connections=0", "", 0, "max-connections must be at least 1");
+ - + - ]
302 [ + - + - : 2 : check_listen_address("unix:,max-connections=-1", "", 0, "max-connections must be at least 1");
+ - + - ]
303 [ + - + - : 2 : check_listen_address("unix:,max-connections=-9223372036854775808", "", 0, "max-connections must be at least 1");
+ - + - ]
304 [ + - + - : 2 : check_listen_address("unix:,max-connections=257", "", 0, "max-connections must be at most 256");
+ - + - ]
305 [ + - + - : 2 : check_listen_address("unix:,max-connections=9223372036854775808", "", 0, "Invalid max-connections value '9223372036854775808'");
+ - + - ]
306 [ + - + - : 2 : check_listen_address("unix:,max-connections=", "", 0, "Missing value for max-connections option");
+ - + - ]
307 [ + - + - : 2 : check_listen_address("unix:path,backup.sock=1", "", 0, "Unknown socket option 'backup.sock'");
+ - + - ]
308 [ + - + - : 2 : check_listen_address("unix:path%2Cbackup.sock=1", "unix:path,backup.sock=1", ipc::DEFAULT_MAX_CONNECTIONS);
+ - + - ]
309 [ + - + - : 2 : check_listen_address("unix:path%2Cbackup.sock=1,max-connections=8", "unix:path,backup.sock=1", 8);
+ - + - ]
310 [ + - + - : 2 : check_listen_address("unix:,max-connections", "", 0, "Missing value for max-connections option");
+ - + - ]
311 [ + - + - : 2 : check_listen_address("unix:,max-connections=2,max-connections=1", "unix:", 1);
+ - + - ]
312 : 2 : }
313 : :
314 : : // Test command line parsing in ipc::Process::checkSpawned().
315 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(check_spawned_test)
+ - + - -
+ + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- ]
316 : : {
317 : 1 : std::unique_ptr<ipc::Process> process{ipc::MakeProcess()};
318 : 1 : char arg0[]{"bitcoin-node"};
319 : 1 : char arg_spawn[]{"-ipcchild"};
320 : 1 : char arg_invalid[]{"invalid"};
321 : 1 : char arg_other[]{"-ipcbind=unix"};
322 : :
323 : : // no -ipcchild arg.
324 : 1 : {
325 : 1 : char* argv[]{arg0};
326 [ + - + - : 2 : BOOST_CHECK(!process->checkSpawned(1, argv));
+ - + - ]
327 : : }
328 : 1 : {
329 : 1 : char* argv[]{arg0, arg_other};
330 [ + - + - : 2 : BOOST_CHECK(!process->checkSpawned(2, argv));
+ - + - ]
331 : : }
332 : 1 : {
333 : 1 : char* argv[]{arg0, arg_other, arg_invalid};
334 [ + - + - : 2 : BOOST_CHECK(!process->checkSpawned(3, argv));
+ - + - ]
335 : : }
336 : : // -ipcchild without a value.
337 : 1 : {
338 : 1 : char* argv[]{arg0, arg_spawn};
339 [ + - + - : 2 : BOOST_CHECK(!process->checkSpawned(2, argv));
+ - + - ]
340 : : }
341 : : // -ipcchild combined with other arguments.
342 : 1 : {
343 : 1 : char* argv[]{arg0, arg_spawn, arg_invalid, arg_other};
344 [ + - + - : 2 : BOOST_CHECK(!process->checkSpawned(4, argv));
+ - + - ]
345 : : }
346 : : // -ipcchild with a value that is not a valid way of connecting to the
347 : : // parent process.
348 : 1 : {
349 : 1 : char* argv[]{arg0, arg_spawn, arg_invalid};
350 [ + - - + : 2 : BOOST_CHECK_THROW(process->checkSpawned(3, argv), std::runtime_error);
- - - - -
+ + - +
- ]
351 : : }
352 : 1 : }
353 : :
354 : : BOOST_AUTO_TEST_SUITE_END()
|