Files
logos-libp2p-module/tests/sync.cpp
T
af85f0ea80 feat: add service discovery (#40)
* feat: add service discovery

- Point nim-libp2p to feat/service-disco/cbind branch
- Update include/libp2p.h with new cbind API (mount_service_discovery,
  all libp2p_service_disco_* functions)
- Add serviceDiscovery option to Libp2pModuleOptions
- Add discoStart/Stop, discoStartDiscovering, discoStopDiscovering,
  discoLookup, discoRandomLookup (async + sync) following the same
  pattern as kad/gossipsub/mix
- Add src/service_discovery.cpp, example, and integration tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Update tests/integration_service_discovery.cpp

Co-authored-by: richΛrd <info@richardramos.me>

* Update include/libp2p.h

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update tests/integration_service_discovery.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* chore: add mountXXX options for mix, kad, service_disco and gossip

* fix: use header from nix pkg

* chore: bump nim-libp2p

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: richΛrd <info@richardramos.me>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-27 09:56:03 -03:00

412 lines
10 KiB
C++

#include <QtTest>
#include <plugin.h>
class TestLibp2pModuleSync : public QObject
{
Q_OBJECT
private slots:
/* ---------------------------
* Connectivity
* --------------------------- */
void testSyncConnectDisconnectPeer()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
QString fakePeer =
"12D3KooWInvalidPeerForTest";
QList<QString> fakeAddrs = {
"/ip4/127.0.0.1/tcp/9999"
};
// connect and disconnect should fail
QVERIFY(!plugin.syncConnectPeer(fakePeer, fakeAddrs).ok);
QVERIFY(!plugin.syncDisconnectPeer(fakePeer).ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncPeerInfo()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
auto res = plugin.syncPeerInfo();
QVERIFY(res.ok);
PeerInfo peerInfo = res.data.value<PeerInfo>();
QVERIFY(!peerInfo.peerId.isEmpty());
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncConnectedPeers()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
auto res = plugin.syncConnectedPeers();
QVERIFY(res.ok);
QList<QString> connectedPeers = res.data.value<QList<QString>>();
QCOMPARE(connectedPeers.size(), 0);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncDial()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
QString fakePeer =
"12D3KooWInvalidPeerForTest";
QString proto = "/test/1.0.0";
QVERIFY(!plugin.syncDial(fakePeer, proto).ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testPublicKey()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
QVERIFY(plugin.syncLibp2pPublicKey().ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
/* ---------------------------
* Stream
* --------------------------- */
void testSyncStreamClose()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
uint64_t fakeStreamId = 1234;
// cannot close inexistent stream
QVERIFY(!plugin.syncStreamClose(fakeStreamId).ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncStreamCloseWithEOF()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
uint64_t fakeStreamId = 1234;
// cannot closeWithEOF inexistent stream
QVERIFY(!plugin.syncStreamCloseWithEOF(fakeStreamId).ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncStreamRelease()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
uint64_t fakeStreamId = 1234;
// cannot release inexistent stream
QVERIFY(!plugin.syncStreamRelease(fakeStreamId).ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncStreamReadExactly()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
uint64_t fakeStreamId = 1234;
size_t len = 16;
// cannot readExactly from inexistent stream
QVERIFY(!plugin.syncStreamReadExactly(fakeStreamId, len).ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncStreamReadLp()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
uint64_t fakeStreamId = 1234;
size_t maxSize = 4096;
// cannot readLp from inexistent stream
QVERIFY(!plugin.syncStreamReadLp(fakeStreamId, maxSize).ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncStreamWrite()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
uint64_t fakeStreamId = 1234;
QByteArray data = "hello-stream";
// cannot write to inexistent stream
QVERIFY(!plugin.syncStreamWrite(fakeStreamId, data).ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncStreamWriteLp()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
uint64_t fakeStreamId = 1234;
QByteArray data = "hello-stream-lp";
// cannot writeLp to inexistent stream
QVERIFY(!plugin.syncStreamWriteLp(fakeStreamId, data).ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
/* ---------------------------
* Gossipsub
* --------------------------- */
void testSyncGossipsubSubscribePublish()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
QString topic = "sync-topic";
QByteArray msg = "sync-gossipsub-msg";
QVERIFY(plugin.syncGossipsubSubscribe(topic).ok);
QVERIFY(plugin.syncGossipsubPublish(topic, msg).ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncGossipsubUnsubscribe()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
QString topic = "sync-topic";
QVERIFY(plugin.syncGossipsubSubscribe(topic).ok);
QVERIFY(plugin.syncGossipsubUnsubscribe(topic).ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
/* ---------------------------
* Kademlia
* --------------------------- */
void testSyncKadGetPutValue()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
QByteArray key = "sync-test-key";
QByteArray value = "sync-hello-world";
QVERIFY(plugin.syncKadPutValue(key, value).ok);
auto res = plugin.syncKadGetValue(key, 1);
QVERIFY(res.ok);
QByteArray actual = res.data.value<QByteArray>();
QCOMPARE(actual, value);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncKeyToCidAndProviders()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
QByteArray key = "sync-provider-test-key";
QByteArray value = "sync-provider-test-value";
auto res = plugin.syncToCid(key);
QVERIFY(res.ok);
QString cid = res.data.value<QString>();
QVERIFY(!cid.isEmpty());
QVERIFY(plugin.syncKadPutValue(key, value).ok);
QVERIFY(plugin.syncKadAddProvider(cid).ok);
// no providers are registered yet
res = plugin.syncKadGetProviders(cid);
QVERIFY(res.ok);
QList<PeerInfo> providers = res.data.value<QList<PeerInfo>>();
QCOMPARE(providers.size(), 0);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncKadFindNode()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
QString fakePeer = "12D3KooWInvalidPeerForSyncTest";
// no nodes are registered yet
QVERIFY(!plugin.syncKadFindNode(fakePeer).ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncKadProvideLifecycle()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
QByteArray key = "sync-providing-key";
auto res = plugin.syncToCid(key);
QVERIFY(res.ok);
QString cid = res.data.value<QString>();
QVERIFY(!cid.isEmpty());
QVERIFY(plugin.syncKadStartProviding(cid).ok);
QVERIFY(plugin.syncKadStopProviding(cid).ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncKadRandomRecords()
{
Libp2pModulePlugin plugin(Libp2pModuleOptions{ .mountServiceDiscovery = true });
QVERIFY(plugin.syncLibp2pStart().ok);
// no registered records yet
auto res = plugin.syncKadGetRandomRecords();
QVERIFY(res.ok);
QVERIFY(res.data.isValid());
QVERIFY(plugin.syncLibp2pStop().ok);
}
/* ---------------------------
* Mix
* --------------------------- */
void testSyncMixDial()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
QString fakePeer = "12D3KooWInvalidMixPeer";
QString addr = "/ip4/127.0.0.1/tcp/9999";
QString proto = "/mix/test/1.0.0";
// expected to fail without a configured mix network
QVERIFY(!plugin.syncMixDial(fakePeer, addr, proto).ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncMixDialWithReply()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
QString fakePeer = "12D3KooWInvalidMixPeer";
QString addr = "/ip4/127.0.0.1/tcp/9999";
QString proto = "/mix/test/1.0.0";
QVERIFY(!plugin.syncMixDialWithReply(
fakePeer,
addr,
proto,
1,
2
).ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncMixRegisterDestReadBehavior()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
QString proto = "/mix/test/1.0.0";
auto res = plugin.syncMixRegisterDestReadBehavior(
proto,
LIBP2P_MIX_READ_EXACTLY,
1024
);
// data should not be valid (cant read)
QVERIFY(!res.data.isValid());
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncMixSetNodeInfo()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
QString addr = "/ip4/127.0.0.1/tcp/4001";
PeerInfo peerInfo = plugin.syncPeerInfo().data.value<PeerInfo>();
QVERIFY(plugin.syncMixSetNodeInfo(peerInfo.addrs[0], plugin.mixGeneratePrivKey()).ok);
QVERIFY(plugin.syncLibp2pStop().ok);
}
void testSyncMixNodepoolAdd()
{
Libp2pModulePlugin plugin;
QVERIFY(plugin.syncLibp2pStart().ok);
QString fakePeer = "12D3KooWInvalidMixPeer";
QString addr = "/ip4/127.0.0.1/tcp/9999";
QByteArray mixPubKey = plugin.mixPublicKey(plugin.mixGeneratePrivKey());
QByteArray fakeLibp2pKey(33, 0x01);
auto res = plugin.syncMixNodepoolAdd(
fakePeer,
addr,
mixPubKey,
fakeLibp2pKey
);
QVERIFY(!res.data.isValid());
QVERIFY(plugin.syncLibp2pStop().ok);
}
};
QTEST_MAIN(TestLibp2pModuleSync)
#include "sync.moc"