Skip to content

Commit

Permalink
chore: add integration tests from libp2p module (#2807)
Browse files Browse the repository at this point in the history
Moves the tests more suited to being integration tests from libp2p
into the integration test module.
  • Loading branch information
achingbrain authored Nov 6, 2024
1 parent 06c4381 commit 6bd7f91
Show file tree
Hide file tree
Showing 8 changed files with 550 additions and 0 deletions.
3 changes: 3 additions & 0 deletions packages/integration-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"@libp2p/kad-dht": "^13.0.0",
"@libp2p/logger": "^5.0.0",
"@libp2p/mdns": "^11.0.0",
"@libp2p/memory": "^0.0.0",
"@libp2p/mplex": "^11.0.0",
"@libp2p/peer-id": "^5.0.0",
"@libp2p/ping": "^2.0.0",
Expand All @@ -62,6 +63,7 @@
"@libp2p/webrtc": "^5.0.0",
"@libp2p/websockets": "^9.0.0",
"@libp2p/webtransport": "^5.0.0",
"@multiformats/dns": "^1.0.6",
"@multiformats/mafmt": "^12.1.6",
"@multiformats/multiaddr": "^12.2.3",
"@multiformats/multiaddr-matcher": "^1.2.1",
Expand All @@ -71,6 +73,7 @@
"execa": "^9.1.0",
"go-libp2p": "^1.5.0",
"it-all": "^3.0.6",
"it-map": "^3.1.1",
"it-pipe": "^3.0.1",
"libp2p": "^2.0.0",
"merge-options": "^3.0.4",
Expand Down
159 changes: 159 additions & 0 deletions packages/integration-tests/test/addresses.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/* eslint-env mocha */

import { memory } from '@libp2p/memory'
import { multiaddr } from '@multiformats/multiaddr'
import { expect } from 'aegir/chai'
import { createLibp2p } from 'libp2p'
import { pEvent } from 'p-event'
import type { Libp2p, PeerUpdate } from '@libp2p/interface'
import type { AddressManager } from '@libp2p/interface-internal'
import type { Multiaddr } from '@multiformats/multiaddr'

const listenAddresses = ['/memory/address-1', '/memory/address-2']
const announceAddresses = ['/dns4/peer.io/tcp/433/p2p/12D3KooWNvSZnPi3RrhrTwEY4LuuBeB6K6facKUCJcyWG1aoDd2p']

describe('addresses', () => {
let libp2p: Libp2p

afterEach(async () => {
await libp2p?.stop()
})

it('should return transport listen addresses if announce addresses are not provided', async () => {
libp2p = await createLibp2p({
addresses: {
listen: listenAddresses
},
transports: [
memory()
]
})

expect(libp2p.getMultiaddrs().map(ma => ma.decapsulate('/p2p').toString())).to.deep.equal(listenAddresses)
})

it('should override listen addresses with announce addresses when provided', async () => {
libp2p = await createLibp2p({
addresses: {
listen: listenAddresses,
announce: announceAddresses
},
transports: [
memory()
]
})

expect(libp2p.getMultiaddrs().map(ma => ma.decapsulate('/p2p').toString())).to.deep.equal(announceAddresses)
})

it('should filter listen addresses filtered by the announce filter', async () => {
libp2p = await createLibp2p({
addresses: {
listen: listenAddresses,
announceFilter: (multiaddrs: Multiaddr[]) => multiaddrs.slice(1)
},
transports: [
memory()
]
})

expect(libp2p.getMultiaddrs().map(ma => ma.decapsulate('/p2p').toString())).to.deep.equal([listenAddresses[1]])
})

it('should filter announce addresses filtered by the announce filter', async () => {
libp2p = await createLibp2p({
addresses: {
listen: listenAddresses,
announce: announceAddresses,
announceFilter: () => []
},
transports: [
memory()
]
})

expect(libp2p.getMultiaddrs().map(ma => ma.decapsulate('/p2p').toString())).to.have.lengthOf(0)
})

it('should include observed addresses in returned multiaddrs', async () => {
const ma = '/ip4/83.32.123.53/tcp/43928'

libp2p = await createLibp2p({
start: false,
addresses: {
listen: listenAddresses
},
transports: [
memory()
],
services: {
observer: (components: { addressManager: AddressManager }) => {
components.addressManager.confirmObservedAddr(multiaddr(ma))
}
}
})

expect(libp2p.getMultiaddrs().map(ma => ma.decapsulate('/p2p').toString())).to.include(ma)
})

it('should update our peer record with announce addresses on startup', async () => {
libp2p = await createLibp2p({
start: false,
addresses: {
listen: listenAddresses,
announce: announceAddresses
},
transports: [
memory()
]
})

const eventPromise = pEvent<'self:peer:update', CustomEvent<PeerUpdate>>(libp2p, 'self:peer:update', {
filter: (event) => {
return event.detail.peer.addresses.map(({ multiaddr }) => multiaddr.toString())
.includes(announceAddresses[0])
}
})

await libp2p.start()

const event = await eventPromise

expect(event.detail.peer.addresses.map(({ multiaddr }) => multiaddr.toString()))
.to.include.members(announceAddresses, 'peer info did not include announce addresses')
})

it('should only include confirmed observed addresses in peer record', async () => {
const unconfirmedAddress = '/ip4/127.0.0.1/tcp/4010/ws'
const confirmedAddress = '/ip4/127.0.0.1/tcp/4011/ws'

libp2p = await createLibp2p({
start: false,
addresses: {
listen: listenAddresses,
announce: announceAddresses
},
transports: [
memory()
],
services: {
observer: (components: { addressManager: AddressManager }) => {
components.addressManager.confirmObservedAddr(multiaddr(confirmedAddress))
components.addressManager.addObservedAddr(multiaddr(unconfirmedAddress))
}
}
})

await libp2p.start()

const eventPromise = pEvent<'self:peer:update', CustomEvent<PeerUpdate>>(libp2p, 'self:peer:update')

const event = await eventPromise

expect(event.detail.peer.addresses.map(({ multiaddr }) => multiaddr.toString()))
.to.not.include(unconfirmedAddress, 'peer info included unconfirmed observed address')

expect(event.detail.peer.addresses.map(({ multiaddr }) => multiaddr.toString()))
.to.include(confirmedAddress, 'peer info did not include confirmed observed address')
})
})
86 changes: 86 additions & 0 deletions packages/integration-tests/test/connections.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/* eslint-env mocha */

import { stop } from '@libp2p/interface'
import { dns } from '@multiformats/dns'
import { multiaddr } from '@multiformats/multiaddr'
import { expect } from 'aegir/chai'
import sinon from 'sinon'
import { createPeers } from './fixtures/create-peers.js'
import type { Echo } from '@libp2p/echo'
import type { Libp2p } from '@libp2p/interface'

describe('connections', () => {
let dialer: Libp2p<{ echo: Echo }>
let listener: Libp2p<{ echo: Echo }>

afterEach(async () => {
await stop(dialer, listener)
})

it('libp2p.getConnections gets the conns', async () => {
({ dialer, listener } = await createPeers())

const conn = await dialer.dial(listener.getMultiaddrs())

expect(conn).to.be.ok()
expect(dialer.getConnections()).to.have.lengthOf(1)
})

it('should open multiple connections when forced', async () => {
({ dialer, listener } = await createPeers())

// connect once, should have one connection
await dialer.dial(listener.getMultiaddrs())
expect(dialer.getConnections()).to.have.lengthOf(1)

// connect twice, should still only have one connection
await dialer.dial(listener.getMultiaddrs())
expect(dialer.getConnections()).to.have.lengthOf(1)

// force connection, should have two connections now
await dialer.dial(listener.getMultiaddrs(), {
force: true
})
expect(dialer.getConnections()).to.have.lengthOf(2)
})

it('should use custom DNS resolver', async () => {
const resolver = sinon.stub()

;({ dialer, listener } = await createPeers({
dns: dns({
resolvers: {
'.': resolver
}
})
}))

const ma = multiaddr('/dnsaddr/example.com/tcp/12345')
const err = new Error('Could not resolve')

resolver.withArgs('_dnsaddr.example.com').rejects(err)

await expect(dialer.dial(ma)).to.eventually.be.rejectedWith(err)
})

it('should fail to dial if resolve fails and there are no addresses to dial', async () => {
const resolver = sinon.stub()

;({ dialer, listener } = await createPeers({
dns: dns({
resolvers: {
'.': resolver
}
})
}))

const ma = multiaddr('/dnsaddr/example.com/tcp/12345')

resolver.withArgs('_dnsaddr.example.com').resolves({
Answer: []
})

await expect(dialer.dial(ma)).to.eventually.be.rejected
.with.property('name', 'NoValidAddressesError')
})
})
38 changes: 38 additions & 0 deletions packages/integration-tests/test/core.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { stop } from '@libp2p/interface'
import { memory } from '@libp2p/memory'
import { multiaddr } from '@multiformats/multiaddr'
import { expect } from 'aegir/chai'
import { createLibp2p } from 'libp2p'
import type { Libp2p } from '@libp2p/interface'

describe('core', () => {
let libp2p: Libp2p

afterEach(async () => {
await stop(libp2p)
})

it('should say an address is dialable if a transport is configured', async () => {
libp2p = await createLibp2p({
transports: [
memory()
]
})

const ma = multiaddr('/memory/address-1')

await expect(libp2p.isDialable(ma)).to.eventually.be.true()
})

it('should say an address is not dialable if a transport is not configured', async () => {
libp2p = await createLibp2p({
transports: [
memory()
]
})

const ma = multiaddr('/ip4/123.123.123.123/tcp/1234')

await expect(libp2p.isDialable(ma)).to.eventually.be.false()
})
})
88 changes: 88 additions & 0 deletions packages/integration-tests/test/events.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { stop } from '@libp2p/interface'
import { expect } from 'aegir/chai'
import pDefer from 'p-defer'
import { createPeers } from './fixtures/create-peers.js'
import type { Echo } from '@libp2p/echo'
import type { Libp2p } from 'libp2p'

describe('events', () => {
let dialer: Libp2p<{ echo: Echo }>
let listener: Libp2p<{ echo: Echo }>

afterEach(async () => {
await stop(dialer, listener)
})

it('should emit connection events', async () => {
({ dialer, listener } = await createPeers())

const localConnectionEventReceived = pDefer()
const localConnectionEndEventReceived = pDefer()
const localPeerConnectEventReceived = pDefer()
const localPeerDisconnectEventReceived = pDefer()
const remoteConnectionEventReceived = pDefer()
const remoteConnectionEndEventReceived = pDefer()
const remotePeerConnectEventReceived = pDefer()
const remotePeerDisconnectEventReceived = pDefer()

dialer.addEventListener('connection:open', (event) => {
expect(event.detail.remotePeer.equals(listener.peerId)).to.be.true()
localConnectionEventReceived.resolve()
})
dialer.addEventListener('connection:close', (event) => {
expect(event.detail.remotePeer.equals(listener.peerId)).to.be.true()
localConnectionEndEventReceived.resolve()
})
dialer.addEventListener('peer:connect', (event) => {
expect(event.detail.equals(listener.peerId)).to.be.true()
localPeerConnectEventReceived.resolve()
})
dialer.addEventListener('peer:disconnect', (event) => {
expect(event.detail.equals(listener.peerId)).to.be.true()
localPeerDisconnectEventReceived.resolve()
})

listener.addEventListener('connection:open', (event) => {
expect(event.detail.remotePeer.equals(dialer.peerId)).to.be.true()
remoteConnectionEventReceived.resolve()
})
listener.addEventListener('connection:close', (event) => {
expect(event.detail.remotePeer.equals(dialer.peerId)).to.be.true()
remoteConnectionEndEventReceived.resolve()
})
listener.addEventListener('peer:connect', (event) => {
expect(event.detail.equals(dialer.peerId)).to.be.true()
remotePeerConnectEventReceived.resolve()
})
listener.addEventListener('peer:disconnect', (event) => {
expect(event.detail.equals(dialer.peerId)).to.be.true()
remotePeerDisconnectEventReceived.resolve()
})

await dialer.dial(listener.getMultiaddrs())

// Verify onConnection is called with the connection
const connections = await Promise.all([
...dialer.getConnections(listener.peerId),
...listener.getConnections(dialer.peerId)
])
expect(connections).to.have.lengthOf(2)

await Promise.all([
localConnectionEventReceived.promise,
localPeerConnectEventReceived.promise,
remoteConnectionEventReceived.promise,
remotePeerConnectEventReceived.promise
])

// Verify onConnectionEnd is called with the connection
await Promise.all(connections.map(async conn => { await conn.close() }))

await Promise.all([
localConnectionEndEventReceived.promise,
localPeerDisconnectEventReceived.promise,
remoteConnectionEndEventReceived.promise,
remotePeerDisconnectEventReceived.promise
])
})
})
Loading

0 comments on commit 6bd7f91

Please sign in to comment.