js-libp2p/test/transports/transport-manager.spec.ts
Alex Potsides f439d9b589
deps!: update all deps to support no-copy operations (#1335)
Updates all deps needed to support passing lists of byte arrays where they have been created from multiple input buffers.

When reading multiplexed data, all messages arrive in length-prefixed buffers, which means the first few bytes tell the consumer how many bytes long next chunk will be.

One length prefixed chunk can be delivered in several payloads from the underlying network transport. The first payload can also include the length prefix and some or all of the data, so we stitch these together in a `Uint8ArrayList` to avoid having to concatenate `Uint8Array`s together.

Previously once we'd received enough bytes to satisfy the length prefix we'd concatenate the bytes together, but this is a potentially expensive operation where transports have small message sizes so instead just pass the `Uint8ArrayList` to the consumer and let them decide wether to concatenate or not as some consumers will be smart enough to operate on lists of `Uint8Array`s instead of always requiring a contiguous block of memory.

BREAKING CHANGE: Streams are now `Duplex<Uint8ArrayList, Uint8ArrayList | Uint8Array>`
2022-08-11 13:21:04 +01:00

159 lines
4.6 KiB
TypeScript

/* eslint-env mocha */
import { expect } from 'aegir/chai'
import sinon from 'sinon'
import { Multiaddr } from '@multiformats/multiaddr'
import { WebSockets } from '@libp2p/websockets'
import * as filters from '@libp2p/websockets/filters'
import { Plaintext } from '../../src/insecure/index.js'
import { DefaultAddressManager } from '../../src/address-manager/index.js'
import { DefaultTransportManager, FaultTolerance } from '../../src/transport-manager.js'
import { mockUpgrader } from '@libp2p/interface-mocks'
import { MULTIADDRS_WEBSOCKETS } from '../fixtures/browser.js'
import { codes as ErrorCodes } from '../../src/errors.js'
import Peers from '../fixtures/peers.js'
import { Components } from '@libp2p/components'
import { createEd25519PeerId, createFromJSON } from '@libp2p/peer-id-factory'
import type { PeerId } from '@libp2p/interface-peer-id'
import { createLibp2pNode, Libp2pNode } from '../../src/libp2p.js'
const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0')
describe('Transport Manager (WebSockets)', () => {
let tm: DefaultTransportManager
let components: Components
before(async () => {
components = new Components({
peerId: await createEd25519PeerId(),
upgrader: mockUpgrader()
})
components.setAddressManager(new DefaultAddressManager(components, { listen: [listenAddr.toString()] }))
tm = new DefaultTransportManager(components)
})
afterEach(async () => {
await tm.removeAll()
expect(tm.getTransports()).to.be.empty()
})
it('should be able to add and remove a transport', async () => {
const transport = new WebSockets({
filter: filters.all
})
expect(tm.getTransports()).to.have.lengthOf(0)
tm.add(transport)
expect(tm.getTransports()).to.have.lengthOf(1)
await tm.remove(transport[Symbol.toStringTag])
expect(tm.getTransports()).to.have.lengthOf(0)
})
it('should not be able to add a transport twice', async () => {
tm.add(new WebSockets())
expect(() => {
tm.add(new WebSockets())
})
.to.throw()
.and.to.have.property('code', ErrorCodes.ERR_DUPLICATE_TRANSPORT)
})
it('should be able to dial', async () => {
tm.add(new WebSockets({ filter: filters.all }))
const addr = MULTIADDRS_WEBSOCKETS[0]
const connection = await tm.dial(addr)
expect(connection).to.exist()
await connection.close()
})
it('should fail to dial an unsupported address', async () => {
tm.add(new WebSockets({ filter: filters.all }))
const addr = new Multiaddr('/ip4/127.0.0.1/tcp/0')
await expect(tm.dial(addr))
.to.eventually.be.rejected()
.and.to.have.property('code', ErrorCodes.ERR_TRANSPORT_UNAVAILABLE)
})
it('should fail to listen with no valid address', async () => {
tm.add(new WebSockets({ filter: filters.all }))
await expect(tm.listen([listenAddr]))
.to.eventually.be.rejected()
.and.to.have.property('code', ErrorCodes.ERR_NO_VALID_ADDRESSES)
})
})
describe('libp2p.transportManager (dial only)', () => {
let peerId: PeerId
let libp2p: Libp2pNode
before(async () => {
peerId = await createFromJSON(Peers[0])
})
afterEach(async () => {
sinon.restore()
if (libp2p != null) {
await libp2p.stop()
}
})
it('fails to start if multiaddr fails to listen', async () => {
libp2p = await createLibp2pNode({
peerId,
addresses: {
listen: ['/ip4/127.0.0.1/tcp/0']
},
transports: [new WebSockets()],
connectionEncryption: [new Plaintext()]
})
await expect(libp2p.start()).to.eventually.be.rejected
.with.property('code', ErrorCodes.ERR_NO_VALID_ADDRESSES)
})
it('does not fail to start if provided listen multiaddr are not compatible to configured transports (when supporting dial only mode)', async () => {
libp2p = await createLibp2pNode({
peerId,
addresses: {
listen: ['/ip4/127.0.0.1/tcp/0']
},
transportManager: {
faultTolerance: FaultTolerance.NO_FATAL
},
transports: [
new WebSockets()
],
connectionEncryption: [
new Plaintext()
]
})
await libp2p.start()
})
it('does not fail to start if provided listen multiaddr fail to listen on configured transports (when supporting dial only mode)', async () => {
libp2p = await createLibp2pNode({
peerId,
addresses: {
listen: ['/ip4/127.0.0.1/tcp/12345/p2p/QmWDn2LY8nannvSWJzruUYoLZ4vV83vfCBwd8DipvdgQc3/p2p-circuit']
},
transportManager: {
faultTolerance: FaultTolerance.NO_FATAL
},
transports: [
new WebSockets()
],
connectionEncryption: [
new Plaintext()
]
})
await libp2p.start()
})
})