Files
logos-libp2p-module/tests/integration.cpp
T

320 lines
11 KiB
C++
Raw Normal View History

2026-05-07 08:01:35 -04:00
#include <logos_test.h>
2026-02-23 11:37:43 -03:00
#include <plugin.h>
2026-05-14 14:11:16 -03:00
#include "test_helpers.h"
2026-05-07 14:34:51 -04:00
2026-05-07 08:01:35 -04:00
LOGOS_TEST(integration_bootstrap_auto_connect) {
2026-05-07 14:34:51 -04:00
Libp2pModuleImpl nodeA;
LOGOS_ASSERT_TRUE(nodeA.start().success);
auto [peerIdA, addrsA] = getPeerInfoPair(nodeA);
2026-02-18 12:04:18 -03:00
2026-05-07 14:34:51 -04:00
Libp2pModuleImpl nodeB(Libp2pModuleOptions{
.bootstrapNodes = { {peerIdA, addrsA} }
});
LOGOS_ASSERT_TRUE(nodeB.start().success);
2026-02-18 12:04:18 -03:00
2026-05-07 14:34:51 -04:00
auto peersRes = nodeB.connectedPeers(Direction_Out);
LOGOS_ASSERT_TRUE(peersRes.success);
auto peers = peersRes.value;
LOGOS_ASSERT_FALSE(peers.empty());
LOGOS_ASSERT_TRUE(peers[0].get<std::string>() == peerIdA);
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.stop().success);
LOGOS_ASSERT_TRUE(nodeB.stop().success);
2026-05-07 08:01:35 -04:00
}
2026-05-07 08:01:35 -04:00
LOGOS_TEST(integration_connect_and_disconnect) {
2026-05-07 14:34:51 -04:00
Libp2pModuleImpl nodeA;
Libp2pModuleImpl nodeB;
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.start().success);
LOGOS_ASSERT_TRUE(nodeB.start().success);
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
auto [peerIdA, addrsA] = getPeerInfoPair(nodeA);
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_FALSE(nodeB.disconnectPeer("fakePeerId").success);
LOGOS_ASSERT_TRUE(nodeB.connectPeer(peerIdA, addrsA, 500).success);
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
auto outPeers = nodeB.connectedPeers(Direction_Out).value;
LOGOS_ASSERT_EQ(outPeers.size(), size_t(1));
auto inPeers = nodeA.connectedPeers(Direction_In).value;
LOGOS_ASSERT_EQ(inPeers.size(), size_t(1));
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeB.disconnectPeer(peerIdA).success);
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.stop().success);
LOGOS_ASSERT_TRUE(nodeB.stop().success);
2026-05-07 08:01:35 -04:00
}
LOGOS_TEST(integration_reconnect_after_disconnect) {
2026-05-07 14:34:51 -04:00
Libp2pModuleImpl nodeA;
Libp2pModuleImpl nodeB;
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.start().success);
LOGOS_ASSERT_TRUE(nodeB.start().success);
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
auto [peerIdB, addrsB] = getPeerInfoPair(nodeB);
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.connectPeer(peerIdB, addrsB, 500).success);
LOGOS_ASSERT_EQ(nodeA.connectedPeers(Direction_Out).value.size(), size_t(1));
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.disconnectPeer(peerIdB).success);
LOGOS_ASSERT_EQ(nodeA.connectedPeers(Direction_Out).value.size(), size_t(0));
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.connectPeer(peerIdB, addrsB, 500).success);
LOGOS_ASSERT_EQ(nodeA.connectedPeers(Direction_Out).value.size(), size_t(1));
2026-05-07 08:01:35 -04:00
const int PING_SIZE = 32;
2026-05-07 14:34:51 -04:00
auto dialResult = nodeA.dial(peerIdB, "/ipfs/ping/1.0.0");
LOGOS_ASSERT_TRUE(dialResult.success);
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
uint64_t streamId = dialResult.value.get<uint64_t>();
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
std::string payload(PING_SIZE, '\0');
2026-05-07 08:01:35 -04:00
for (int i = 0; i < PING_SIZE; ++i)
payload[i] = static_cast<char>(i);
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.streamWrite(streamId, payload).success);
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
auto readResult = nodeA.streamReadExactly(streamId, PING_SIZE);
LOGOS_ASSERT_TRUE(readResult.success);
2026-06-25 10:10:16 -03:00
LOGOS_ASSERT_TRUE(base64Decode(readResult.value.get<std::string>()) == payload);
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.streamCloseWithEOF(streamId).success);
LOGOS_ASSERT_TRUE(nodeA.streamRelease(streamId).success);
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.stop().success);
LOGOS_ASSERT_TRUE(nodeB.stop().success);
2026-05-07 08:01:35 -04:00
}
LOGOS_TEST(integration_multiple_streams_on_same_connection) {
const int PING_SIZE = 32;
2026-05-07 14:34:51 -04:00
Libp2pModuleImpl nodeA;
Libp2pModuleImpl nodeB;
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.start().success);
LOGOS_ASSERT_TRUE(nodeB.start().success);
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
auto [peerIdB, addrsB] = getPeerInfoPair(nodeB);
LOGOS_ASSERT_TRUE(nodeA.connectPeer(peerIdB, addrsB, 500).success);
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
auto dial1 = nodeA.dial(peerIdB, "/ipfs/ping/1.0.0");
LOGOS_ASSERT_TRUE(dial1.success);
uint64_t stream1 = dial1.value.get<uint64_t>();
2026-05-07 08:01:35 -04:00
2026-05-07 14:34:51 -04:00
auto dial2 = nodeA.dial(peerIdB, "/ipfs/ping/1.0.0");
LOGOS_ASSERT_TRUE(dial2.success);
uint64_t stream2 = dial2.value.get<uint64_t>();
2026-05-07 08:01:35 -04:00
LOGOS_ASSERT_NE(stream1, stream2);
2026-05-07 14:34:51 -04:00
std::string payload1(PING_SIZE, '\0');
std::string payload2(PING_SIZE, '\0');
2026-05-07 08:01:35 -04:00
for (int i = 0; i < PING_SIZE; ++i) {
payload1[i] = static_cast<char>(i);
payload2[i] = static_cast<char>(255 - i);
}
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.streamWrite(stream1, payload1).success);
LOGOS_ASSERT_TRUE(nodeA.streamWrite(stream2, payload2).success);
2026-02-18 12:04:18 -03:00
2026-05-07 14:34:51 -04:00
auto read1 = nodeA.streamReadExactly(stream1, PING_SIZE);
LOGOS_ASSERT_TRUE(read1.success);
2026-06-25 10:10:16 -03:00
LOGOS_ASSERT_TRUE(base64Decode(read1.value.get<std::string>()) == payload1);
2026-02-18 12:04:18 -03:00
2026-05-07 14:34:51 -04:00
auto read2 = nodeA.streamReadExactly(stream2, PING_SIZE);
LOGOS_ASSERT_TRUE(read2.success);
2026-06-25 10:10:16 -03:00
LOGOS_ASSERT_TRUE(base64Decode(read2.value.get<std::string>()) == payload2);
2026-02-18 12:04:18 -03:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.streamCloseWithEOF(stream1).success);
LOGOS_ASSERT_TRUE(nodeA.streamRelease(stream1).success);
LOGOS_ASSERT_TRUE(nodeA.streamCloseWithEOF(stream2).success);
LOGOS_ASSERT_TRUE(nodeA.streamRelease(stream2).success);
2026-02-18 12:04:18 -03:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.stop().success);
LOGOS_ASSERT_TRUE(nodeB.stop().success);
2026-05-07 08:01:35 -04:00
}
2026-03-02 15:08:33 -03:00
2026-05-07 08:01:35 -04:00
LOGOS_TEST(integration_direct_dial_stream_exchange) {
const int PING_SIZE = 32;
2026-03-02 15:08:33 -03:00
2026-05-07 14:34:51 -04:00
Libp2pModuleImpl nodeA;
Libp2pModuleImpl nodeB;
2026-03-02 15:08:33 -03:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.start().success);
LOGOS_ASSERT_TRUE(nodeB.start().success);
2026-02-18 12:04:18 -03:00
2026-05-07 14:34:51 -04:00
auto [peerIdB, addrsB] = getPeerInfoPair(nodeB);
LOGOS_ASSERT_TRUE(nodeA.connectPeer(peerIdB, addrsB, 500).success);
2026-02-18 12:04:18 -03:00
2026-05-07 14:34:51 -04:00
auto dialResult = nodeA.dial(peerIdB, "/ipfs/ping/1.0.0");
LOGOS_ASSERT_TRUE(dialResult.success);
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
uint64_t streamId = dialResult.value.get<uint64_t>();
2026-05-07 08:01:35 -04:00
LOGOS_ASSERT_NE(streamId, static_cast<uint64_t>(0));
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
std::string payload(PING_SIZE, '\0');
2026-05-07 08:01:35 -04:00
for (int i = 0; i < PING_SIZE; ++i)
payload[i] = static_cast<char>(i);
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.streamWrite(streamId, payload).success);
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
auto readResult = nodeA.streamReadExactly(streamId, PING_SIZE);
LOGOS_ASSERT_TRUE(readResult.success);
2026-06-25 10:10:16 -03:00
LOGOS_ASSERT_TRUE(base64Decode(readResult.value.get<std::string>()) == payload);
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.streamCloseWithEOF(streamId).success);
LOGOS_ASSERT_TRUE(nodeA.streamRelease(streamId).success);
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.stop().success);
LOGOS_ASSERT_TRUE(nodeB.stop().success);
2026-05-07 08:01:35 -04:00
}
2026-03-12 23:16:00 +00:00
2026-05-07 08:01:35 -04:00
LOGOS_TEST(integration_circuit_relay_routing) {
const int PING_SIZE = 32;
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
Libp2pModuleImpl relay(Libp2pModuleOptions{ .circuitRelay = true });
LOGOS_ASSERT_TRUE(relay.start().success);
auto [relayPeerId, relayAddrs] = getPeerInfoPair(relay);
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
Libp2pModuleImpl nodeA(Libp2pModuleOptions{ .circuitRelayClient = true });
LOGOS_ASSERT_TRUE(nodeA.start().success);
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
Libp2pModuleImpl nodeB(Libp2pModuleOptions{ .circuitRelayClient = true });
LOGOS_ASSERT_TRUE(nodeB.start().success);
auto [peerIdB, addrsB] = getPeerInfoPair(nodeB);
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.connectPeer(relayPeerId, relayAddrs, 500).success);
LOGOS_ASSERT_TRUE(nodeB.connectPeer(relayPeerId, relayAddrs, 500).success);
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
auto rsvp = nodeB.circuitRelayReserve(relayPeerId, relayAddrs);
LOGOS_ASSERT_TRUE(rsvp.success);
auto rsvpAddrs = rsvp.value;
LOGOS_ASSERT_FALSE(rsvpAddrs.empty());
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
std::string relayAddr = rsvpAddrs[0].get<std::string>() + "/p2p-circuit";
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
auto dialResult = nodeA.dialCircuitRelay(peerIdB, relayAddr, "/ipfs/ping/1.0.0");
LOGOS_ASSERT_TRUE(dialResult.success);
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
uint64_t streamId = dialResult.value.get<uint64_t>();
2026-05-07 08:01:35 -04:00
LOGOS_ASSERT_NE(streamId, static_cast<uint64_t>(0));
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
std::string payload(PING_SIZE, '\0');
2026-05-07 08:01:35 -04:00
for (int i = 0; i < PING_SIZE; ++i)
payload[i] = static_cast<char>(i);
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.streamWrite(streamId, payload).success);
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
auto readResult = nodeA.streamReadExactly(streamId, PING_SIZE);
LOGOS_ASSERT_TRUE(readResult.success);
2026-06-25 10:10:16 -03:00
LOGOS_ASSERT_TRUE(base64Decode(readResult.value.get<std::string>()) == payload);
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.streamCloseWithEOF(streamId).success);
LOGOS_ASSERT_TRUE(nodeA.streamRelease(streamId).success);
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(relay.stop().success);
LOGOS_ASSERT_TRUE(nodeA.stop().success);
LOGOS_ASSERT_TRUE(nodeB.stop().success);
2026-05-07 08:01:35 -04:00
}
2026-03-12 23:16:00 +00:00
2026-05-07 08:01:35 -04:00
LOGOS_TEST(integration_lp_stream_exchange) {
const int LP_PAYLOAD_SIZE = 31;
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
Libp2pModuleImpl nodeA;
Libp2pModuleImpl nodeB;
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.start().success);
LOGOS_ASSERT_TRUE(nodeB.start().success);
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
auto [peerIdB, addrsB] = getPeerInfoPair(nodeB);
LOGOS_ASSERT_TRUE(nodeA.connectPeer(peerIdB, addrsB, 500).success);
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
auto dialResult = nodeA.dial(peerIdB, "/ipfs/ping/1.0.0");
LOGOS_ASSERT_TRUE(dialResult.success);
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
uint64_t streamId = dialResult.value.get<uint64_t>();
2026-05-07 08:01:35 -04:00
LOGOS_ASSERT_NE(streamId, static_cast<uint64_t>(0));
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
std::string payload(LP_PAYLOAD_SIZE, '\0');
2026-05-07 08:01:35 -04:00
for (int i = 0; i < LP_PAYLOAD_SIZE; ++i)
payload[i] = static_cast<char>(i);
2026-03-12 23:16:00 +00:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.streamWriteLp(streamId, payload).success);
2026-03-14 10:12:36 +00:00
2026-05-07 14:34:51 -04:00
auto readResult = nodeA.streamReadLp(streamId, 4096);
LOGOS_ASSERT_TRUE(readResult.success);
2026-06-25 10:10:16 -03:00
LOGOS_ASSERT_TRUE(base64Decode(readResult.value.get<std::string>()) == payload);
2026-03-14 10:12:36 +00:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.streamCloseWithEOF(streamId).success);
LOGOS_ASSERT_TRUE(nodeA.streamRelease(streamId).success);
2026-03-14 10:12:36 +00:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.stop().success);
LOGOS_ASSERT_TRUE(nodeB.stop().success);
2026-05-07 08:01:35 -04:00
}
2026-03-14 10:12:36 +00:00
LOGOS_TEST(integration_create_node_then_node_info) {
Libp2pModuleImpl node;
LOGOS_ASSERT_TRUE(node.createNode(R"({"addrs": ["/ip4/127.0.0.1/tcp/0"]})").success);
LOGOS_ASSERT_TRUE(node.start().success);
auto version = node.getNodeInfo("Version");
LOGOS_ASSERT_TRUE(version.success);
LOGOS_ASSERT_TRUE(version.value.get<std::string>() == "1.0.0");
auto ports = node.getNodeInfo("MyBoundPorts");
LOGOS_ASSERT_TRUE(ports.success);
LOGOS_ASSERT_FALSE(ports.value.empty());
LOGOS_ASSERT_TRUE(ports.value[0].get<int>() > 0);
auto peerId = node.getNodeInfo("PeerId");
LOGOS_ASSERT_TRUE(peerId.success);
LOGOS_ASSERT_FALSE(peerId.value.get<std::string>().empty());
LOGOS_ASSERT_FALSE(node.getNodeInfo("Nonexistent").success);
LOGOS_ASSERT_TRUE(node.stop().success);
}
LOGOS_TEST(integration_create_node_invalid_config_fails) {
Libp2pModuleImpl node;
auto res = node.createNode("{not valid json");
LOGOS_ASSERT_FALSE(res.success);
LOGOS_ASSERT_TRUE(res.error.find("invalid config") != std::string::npos);
}
2026-05-07 08:01:35 -04:00
LOGOS_TEST(integration_quic_ping_round_trip) {
const int PING_SIZE = 32;
2026-03-14 10:12:36 +00:00
2026-05-07 08:01:35 -04:00
Libp2pModuleOptions opts{ .transport = LIBP2P_TRANSPORT_QUIC };
2026-03-14 10:12:36 +00:00
2026-05-07 14:34:51 -04:00
Libp2pModuleImpl nodeA(opts);
Libp2pModuleImpl nodeB(opts);
2026-03-14 10:12:36 +00:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.start().success);
LOGOS_ASSERT_TRUE(nodeB.start().success);
2026-03-14 10:12:36 +00:00
2026-05-07 14:34:51 -04:00
auto [peerIdB, addrsB] = getPeerInfoPair(nodeB);
2026-06-29 17:31:43 -03:00
// QUIC's TLS handshake under ThreadSanitizer can exceed a 500ms deadline.
LOGOS_ASSERT_TRUE(nodeA.connectPeer(peerIdB, addrsB, 5000).success);
2026-03-14 10:12:36 +00:00
2026-05-07 14:34:51 -04:00
auto dialResult = nodeA.dial(peerIdB, "/ipfs/ping/1.0.0");
LOGOS_ASSERT_TRUE(dialResult.success);
2026-03-14 10:12:36 +00:00
2026-05-07 14:34:51 -04:00
uint64_t streamId = dialResult.value.get<uint64_t>();
2026-05-07 08:01:35 -04:00
LOGOS_ASSERT_NE(streamId, static_cast<uint64_t>(0));
2026-03-14 10:12:36 +00:00
2026-05-07 14:34:51 -04:00
std::string payload(PING_SIZE, '\0');
2026-05-07 08:01:35 -04:00
for (int i = 0; i < PING_SIZE; ++i)
payload[i] = static_cast<char>(i);
2026-03-14 10:12:36 +00:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.streamWrite(streamId, payload).success);
2026-03-22 21:22:12 +00:00
2026-05-07 14:34:51 -04:00
auto readResult = nodeA.streamReadExactly(streamId, PING_SIZE);
LOGOS_ASSERT_TRUE(readResult.success);
2026-06-25 10:10:16 -03:00
LOGOS_ASSERT_TRUE(base64Decode(readResult.value.get<std::string>()) == payload);
2026-03-22 21:22:12 +00:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.streamCloseWithEOF(streamId).success);
LOGOS_ASSERT_TRUE(nodeA.streamRelease(streamId).success);
2026-03-22 21:22:12 +00:00
2026-05-07 14:34:51 -04:00
LOGOS_ASSERT_TRUE(nodeA.stop().success);
LOGOS_ASSERT_TRUE(nodeB.stop().success);
2026-05-07 08:01:35 -04:00
}