mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-04-25 10:32:14 +00:00
Instead of making the `.dht` and `.pubsub` properties optional, use dummy implementations that throw exceptions if they are not configured. This way we don't have to null guard everywhere they are accessed.
179 lines
5.5 KiB
TypeScript
179 lines
5.5 KiB
TypeScript
/* eslint-env mocha */
|
|
|
|
import { expect } from 'aegir/chai'
|
|
import { Multiaddr } from '@multiformats/multiaddr'
|
|
import pWaitFor from 'p-wait-for'
|
|
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|
import { subsystemMulticodecs, createSubsystemOptions } from './utils.js'
|
|
import { createPeerId } from '../../utils/creators/peer.js'
|
|
import type { PeerId } from '@libp2p/interfaces/peer-id'
|
|
import { createLibp2pNode, Libp2pNode } from '../../../src/libp2p.js'
|
|
import { isStartable } from '@libp2p/interfaces'
|
|
|
|
const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/8000')
|
|
const remoteListenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/8001')
|
|
|
|
async function getRemoteAddr (remotePeerId: PeerId, libp2p: Libp2pNode) {
|
|
const addrs = await libp2p.components.getPeerStore().addressBook.get(remotePeerId)
|
|
|
|
if (addrs.length === 0) {
|
|
throw new Error('No addrs found')
|
|
}
|
|
|
|
const addr = addrs[0]
|
|
|
|
return addr.multiaddr.encapsulate(`/p2p/${remotePeerId.toString()}`)
|
|
}
|
|
|
|
describe('DHT subsystem operates correctly', () => {
|
|
let peerId: PeerId, remotePeerId: PeerId
|
|
let libp2p: Libp2pNode, remoteLibp2p: Libp2pNode
|
|
let remAddr: Multiaddr
|
|
|
|
beforeEach(async () => {
|
|
[peerId, remotePeerId] = await Promise.all([
|
|
createPeerId(),
|
|
createPeerId()
|
|
])
|
|
})
|
|
|
|
describe('dht started before connect', () => {
|
|
beforeEach(async () => {
|
|
libp2p = await createLibp2pNode(createSubsystemOptions({
|
|
peerId,
|
|
addresses: {
|
|
listen: [listenAddr.toString()]
|
|
}
|
|
}))
|
|
|
|
remoteLibp2p = await createLibp2pNode(createSubsystemOptions({
|
|
peerId: remotePeerId,
|
|
addresses: {
|
|
listen: [remoteListenAddr.toString()]
|
|
}
|
|
}))
|
|
|
|
await Promise.all([
|
|
libp2p.start(),
|
|
remoteLibp2p.start()
|
|
])
|
|
|
|
await libp2p.components.getPeerStore().addressBook.set(remotePeerId, [remoteListenAddr])
|
|
remAddr = await getRemoteAddr(remotePeerId, libp2p)
|
|
})
|
|
|
|
afterEach(async () => {
|
|
if (libp2p != null) {
|
|
await libp2p.stop()
|
|
}
|
|
|
|
if (remoteLibp2p != null) {
|
|
await remoteLibp2p.stop()
|
|
}
|
|
})
|
|
|
|
it('should get notified of connected peers on dial', async () => {
|
|
const connection = await libp2p.dialProtocol(remAddr, subsystemMulticodecs)
|
|
|
|
expect(connection).to.exist()
|
|
|
|
return await Promise.all([
|
|
pWaitFor(() => libp2p.dht.lan.routingTable.size === 1),
|
|
pWaitFor(() => remoteLibp2p.dht.lan.routingTable.size === 1)
|
|
])
|
|
})
|
|
|
|
it('should put on a peer and get from the other', async () => {
|
|
const key = uint8ArrayFromString('hello')
|
|
const value = uint8ArrayFromString('world')
|
|
|
|
await libp2p.dialProtocol(remAddr, subsystemMulticodecs)
|
|
await Promise.all([
|
|
pWaitFor(() => libp2p.dht.lan.routingTable.size === 1),
|
|
pWaitFor(() => remoteLibp2p.dht.lan.routingTable.size === 1)
|
|
])
|
|
|
|
await libp2p.components.getContentRouting().put(key, value)
|
|
|
|
const fetchedValue = await remoteLibp2p.components.getContentRouting().get(key)
|
|
expect(fetchedValue).to.equalBytes(value)
|
|
})
|
|
})
|
|
|
|
describe('dht started after connect', () => {
|
|
beforeEach(async () => {
|
|
libp2p = await createLibp2pNode(createSubsystemOptions({
|
|
peerId,
|
|
addresses: {
|
|
listen: [listenAddr.toString()]
|
|
}
|
|
}))
|
|
|
|
remoteLibp2p = await createLibp2pNode(createSubsystemOptions({
|
|
peerId: remotePeerId,
|
|
addresses: {
|
|
listen: [remoteListenAddr.toString()]
|
|
}
|
|
}))
|
|
|
|
await libp2p.start()
|
|
await remoteLibp2p.start()
|
|
|
|
await libp2p.components.getPeerStore().addressBook.set(remotePeerId, [remoteListenAddr])
|
|
remAddr = await getRemoteAddr(remotePeerId, libp2p)
|
|
})
|
|
|
|
afterEach(async () => {
|
|
if (libp2p != null) {
|
|
await libp2p.stop()
|
|
}
|
|
|
|
if (remoteLibp2p != null) {
|
|
await remoteLibp2p.stop()
|
|
}
|
|
})
|
|
|
|
// TODO: we pre-fill the routing tables on dht startup with artificial peers so this test
|
|
// doesn't really work as intended. We should be testing that a connected peer can change
|
|
// it's supported protocols and we should notice that change so there may be something to
|
|
// salvage from here, though it could be better as identify protocol tests.
|
|
it.skip('should get notified of connected peers after starting', async () => {
|
|
const connection = await libp2p.dial(remAddr)
|
|
|
|
expect(connection).to.exist()
|
|
expect(libp2p.dht.lan.routingTable).to.be.empty()
|
|
|
|
const dht = remoteLibp2p.dht
|
|
|
|
if (isStartable(dht)) {
|
|
await dht.start()
|
|
}
|
|
|
|
// should be 0 directly after start - TODO this may be susceptible to timing bugs, we should have
|
|
// the ability to report stats on the DHT routing table instead of reaching into it's heart like this
|
|
expect(remoteLibp2p.dht.lan.routingTable).to.be.empty()
|
|
|
|
return await pWaitFor(() => libp2p.dht.lan.routingTable.size === 1)
|
|
})
|
|
|
|
it('should put on a peer and get from the other', async () => {
|
|
await libp2p.dial(remAddr)
|
|
|
|
const key = uint8ArrayFromString('hello')
|
|
const value = uint8ArrayFromString('world')
|
|
|
|
const dht = remoteLibp2p.dht
|
|
|
|
if (isStartable(dht)) {
|
|
await dht.start()
|
|
}
|
|
|
|
await pWaitFor(() => libp2p.dht.lan.routingTable.size === 1)
|
|
await libp2p.components.getContentRouting().put(key, value)
|
|
|
|
const fetchedValue = await remoteLibp2p.components.getContentRouting().get(key)
|
|
expect(fetchedValue).to.equalBytes(value)
|
|
})
|
|
})
|
|
})
|