Skip to content
This repository was archived by the owner on Jun 26, 2023. It is now read-only.

Commit a367375

Browse files
authored
fix: move connection manager mock to connection manager module (#205)
Also add mock network to enable dialing other peers by mocks. Components now control the start/stop lifecycle of their components.
1 parent 8c312de commit a367375

File tree

22 files changed

+626
-389
lines changed

22 files changed

+626
-389
lines changed

packages/libp2p-interface-compliance-tests/src/mocks/connection-manager.ts

Lines changed: 125 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,137 @@
1-
import { EventEmitter } from '@libp2p/interfaces'
1+
import { CustomEvent, EventEmitter, Startable } from '@libp2p/interfaces'
22
import type { Connection } from '@libp2p/interfaces/connection'
33
import type { PeerId } from '@libp2p/interfaces/peer-id'
4-
import type { ConnectionManager, ConnectionManagerEvents } from '@libp2p/interfaces/registrar'
4+
import type { ConnectionManager, ConnectionManagerEvents } from '@libp2p/interfaces/connection-manager'
5+
import type { Components, Initializable } from '@libp2p/interfaces/src/components'
6+
import { connectionPair } from './connection.js'
7+
import errCode from 'err-code'
58

6-
class MockConnectionManager extends EventEmitter<ConnectionManagerEvents> implements ConnectionManager {
7-
getConnectionMap (): Map<string, Connection[]> {
8-
return new Map<string, Connection[]>()
9+
class MockNetwork {
10+
private components: Components[] = []
11+
12+
addNode (components: Components): void {
13+
this.components.push(components)
14+
}
15+
16+
getNode (peerId: PeerId): Components {
17+
for (const components of this.components) {
18+
if (peerId.equals(components.getPeerId())) {
19+
return components
20+
}
21+
}
22+
23+
throw errCode(new Error('Peer not found'), 'ERR_PEER_NOT_FOUND')
24+
}
25+
26+
reset () {
27+
this.components = []
28+
}
29+
}
30+
31+
export const mockNetwork = new MockNetwork()
32+
33+
class MockConnectionManager extends EventEmitter<ConnectionManagerEvents> implements ConnectionManager, Initializable, Startable {
34+
private connections: Connection[] = []
35+
private components?: Components
36+
private started = false
37+
38+
init (components: Components) {
39+
this.components = components
40+
}
41+
42+
isStarted () {
43+
return this.started
44+
}
45+
46+
async start () {
47+
this.started = true
48+
}
49+
50+
async stop () {
51+
for (const connection of this.connections) {
52+
await this.closeConnections(connection.remotePeer)
53+
}
54+
55+
this.started = false
956
}
1057

11-
getConnectionList (): Connection[] {
12-
return []
58+
getConnections (peerId?: PeerId): Connection[] {
59+
if (peerId != null) {
60+
return this.connections
61+
.filter(c => c.remotePeer.toString() === peerId.toString())
62+
}
63+
64+
return this.connections
1365
}
1466

15-
getConnections (): Connection[] {
16-
return []
67+
async openConnection (peerId: PeerId) {
68+
if (this.components == null) {
69+
throw errCode(new Error('Not initialized'), 'ERR_NOT_INITIALIZED')
70+
}
71+
72+
const existingConnections = this.getConnections(peerId)
73+
74+
if (existingConnections.length > 0) {
75+
return existingConnections[0]
76+
}
77+
78+
const componentsB = mockNetwork.getNode(peerId)
79+
80+
const [aToB, bToA] = connectionPair(this.components, componentsB)
81+
82+
// track connections
83+
this.connections.push(aToB)
84+
;(componentsB.getConnectionManager() as MockConnectionManager).connections.push(bToA)
85+
86+
this.components.getConnectionManager().dispatchEvent(new CustomEvent<Connection>('peer:connect', {
87+
detail: aToB
88+
}))
89+
90+
for (const protocol of this.components.getRegistrar().getProtocols()) {
91+
for (const topology of this.components.getRegistrar().getTopologies(protocol)) {
92+
topology.onConnect(componentsB.getPeerId(), aToB)
93+
}
94+
}
95+
96+
componentsB.getConnectionManager().dispatchEvent(new CustomEvent<Connection>('peer:connect', {
97+
detail: bToA
98+
}))
99+
100+
for (const protocol of componentsB.getRegistrar().getProtocols()) {
101+
for (const topology of componentsB.getRegistrar().getTopologies(protocol)) {
102+
topology.onConnect(this.components.getPeerId(), bToA)
103+
}
104+
}
105+
106+
return aToB
17107
}
18108

19-
getConnection (peerId: PeerId): Connection | undefined {
20-
return undefined
109+
async closeConnections (peerId: PeerId) {
110+
if (this.components == null) {
111+
throw errCode(new Error('Not initialized'), 'ERR_NOT_INITIALIZED')
112+
}
113+
114+
const connections = this.getConnections(peerId)
115+
116+
if (connections.length === 0) {
117+
return
118+
}
119+
120+
const componentsB = mockNetwork.getNode(peerId)
121+
122+
for (const protocol of this.components.getRegistrar().getProtocols()) {
123+
this.components.getRegistrar().getTopologies(protocol).forEach(topology => {
124+
topology.onDisconnect(componentsB.getPeerId())
125+
})
126+
}
127+
128+
for (const conn of connections) {
129+
await conn.close()
130+
}
131+
132+
this.connections = this.connections.filter(c => !c.remotePeer.equals(peerId))
133+
134+
await componentsB.getConnectionManager().closeConnections(peerId)
21135
}
22136
}
23137

packages/libp2p-interface-compliance-tests/src/mocks/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
export { mockConnectionGater } from './connection-gater.js'
3-
export { mockConnectionManager } from './connection-manager.js'
3+
export { mockConnectionManager, mockNetwork } from './connection-manager.js'
44
export { mockConnection, mockStream, connectionPair } from './connection.js'
55
export { mockMultiaddrConnection, mockMultiaddrConnPair } from './multiaddr-connection.js'
66
export { mockMuxer } from './muxer.js'

packages/libp2p-interface-compliance-tests/src/mocks/registrar.ts

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import type { IncomingStreamData, Registrar, StreamHandler } from '@libp2p/inter
22
import type { Connection } from '@libp2p/interfaces/connection'
33
import type { PeerId } from '@libp2p/interfaces/peer-id'
44
import type { Topology } from '@libp2p/interfaces/topology'
5-
import { connectionPair } from './connection.js'
6-
import type { Components } from '@libp2p/interfaces/src/components'
75

86
export class MockRegistrar implements Registrar {
97
private readonly topologies: Map<string, { topology: Topology, protocols: string[] }> = new Map()
@@ -89,7 +87,7 @@ export class MockRegistrar implements Registrar {
8987
return output
9088
}
9189

92-
throw new Error(`No topologies registered for protocol ${protocol}`)
90+
return []
9391
}
9492
}
9593

@@ -106,16 +104,3 @@ export async function mockIncomingStreamEvent (protocol: string, conn: Connectio
106104
}
107105
}
108106
}
109-
110-
export async function connectPeers (protocol: string, a: Components, b: Components) {
111-
// Notify peers of connection
112-
const [aToB, bToA] = connectionPair(a, b)
113-
114-
for (const topology of a.getRegistrar().getTopologies(protocol)) {
115-
await topology.onConnect(b.getPeerId(), aToB)
116-
}
117-
118-
for (const topology of b.getRegistrar().getTopologies(protocol)) {
119-
await topology.onConnect(a.getPeerId(), bToA)
120-
}
121-
}

packages/libp2p-interface-compliance-tests/src/pubsub/api.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import type { Components } from '@libp2p/interfaces/components'
1111
import { createComponents } from './utils.js'
1212
import { start, stop } from '../index.js'
1313
import { isStartable } from '@libp2p/interfaces'
14+
import { mockNetwork } from '../mocks/connection-manager.js'
1415

1516
const topic = 'foo'
1617
const data = uint8ArrayFromString('bar')
@@ -22,20 +23,22 @@ export default (common: TestSetup<PubSub, PubSubArgs>) => {
2223

2324
// Create pubsub router
2425
beforeEach(async () => {
26+
mockNetwork.reset()
2527
components = await createComponents()
2628

27-
pubsub = await common.setup({
29+
pubsub = components.setPubSub(await common.setup({
2830
components,
2931
init: {
3032
emitSelf: true
3133
}
32-
})
34+
}))
3335
})
3436

3537
afterEach(async () => {
3638
sinon.restore()
37-
await stop(pubsub)
39+
await stop(common)
3840
await common.teardown()
41+
mockNetwork.reset()
3942
})
4043

4144
it('can start correctly', async () => {
@@ -45,7 +48,7 @@ export default (common: TestSetup<PubSub, PubSubArgs>) => {
4548

4649
sinon.spy(components.getRegistrar(), 'register')
4750

48-
await pubsub.start()
51+
await start(components)
4952

5053
expect(pubsub.isStarted()).to.equal(true)
5154
expect(components.getRegistrar().register).to.have.property('callCount', 1)
@@ -58,8 +61,8 @@ export default (common: TestSetup<PubSub, PubSubArgs>) => {
5861

5962
sinon.spy(components.getRegistrar(), 'unregister')
6063

61-
await pubsub.start()
62-
await pubsub.stop()
64+
await start(components)
65+
await stop(components)
6366

6467
expect(pubsub.isStarted()).to.equal(false)
6568
expect(components.getRegistrar().unregister).to.have.property('callCount', 1)
@@ -70,7 +73,7 @@ export default (common: TestSetup<PubSub, PubSubArgs>) => {
7073
throw new Error('a message should not be received')
7174
}
7275

73-
await start(pubsub)
76+
await start(components)
7477
pubsub.subscribe(topic)
7578
pubsub.addEventListener('message', handler)
7679

@@ -90,13 +93,13 @@ export default (common: TestSetup<PubSub, PubSubArgs>) => {
9093
// handlers are called async
9194
await delay(100)
9295

93-
await stop(pubsub)
96+
await stop(components)
9497
})
9598

9699
it('can subscribe and publish correctly', async () => {
97100
const defer = pDefer()
98101

99-
await start(pubsub)
102+
await start(components)
100103

101104
pubsub.subscribe(topic)
102105
pubsub.addEventListener('message', (evt) => {
@@ -107,7 +110,7 @@ export default (common: TestSetup<PubSub, PubSubArgs>) => {
107110
await pubsub.publish(topic, data)
108111
await defer.promise
109112

110-
await stop(pubsub)
113+
await stop(components)
111114
})
112115
})
113116
}

0 commit comments

Comments
 (0)