@libp2p/interface-compliance-tests 3.0.7-ab0e3980 → 3.0.7-b36ec7f2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/README.md +9 -0
  2. package/dist/src/connection/index.d.ts +5 -0
  3. package/dist/src/connection/index.d.ts.map +1 -0
  4. package/dist/src/connection/index.js +150 -0
  5. package/dist/src/connection/index.js.map +1 -0
  6. package/dist/src/connection-encryption/index.d.ts +5 -0
  7. package/dist/src/connection-encryption/index.d.ts.map +1 -0
  8. package/dist/src/connection-encryption/index.js +71 -0
  9. package/dist/src/connection-encryption/index.js.map +1 -0
  10. package/dist/src/connection-encryption/utils/index.d.ts +3 -0
  11. package/dist/src/connection-encryption/utils/index.d.ts.map +1 -0
  12. package/dist/src/connection-encryption/utils/index.js +19 -0
  13. package/dist/src/connection-encryption/utils/index.js.map +1 -0
  14. package/dist/src/mocks/connection-encrypter.d.ts +3 -0
  15. package/dist/src/mocks/connection-encrypter.d.ts.map +1 -0
  16. package/dist/src/mocks/connection-encrypter.js +98 -0
  17. package/dist/src/mocks/connection-encrypter.js.map +1 -0
  18. package/dist/src/mocks/connection-gater.d.ts +3 -0
  19. package/dist/src/mocks/connection-gater.d.ts.map +1 -0
  20. package/dist/src/mocks/connection-gater.js +17 -0
  21. package/dist/src/mocks/connection-gater.js.map +1 -0
  22. package/dist/src/mocks/connection-manager.d.ts +29 -0
  23. package/dist/src/mocks/connection-manager.d.ts.map +1 -0
  24. package/dist/src/mocks/connection-manager.js +145 -0
  25. package/dist/src/mocks/connection-manager.js.map +1 -0
  26. package/dist/src/mocks/connection.d.ts +32 -0
  27. package/dist/src/mocks/connection.d.ts.map +1 -0
  28. package/dist/src/mocks/connection.js +165 -0
  29. package/dist/src/mocks/connection.js.map +1 -0
  30. package/dist/src/mocks/duplex.d.ts +3 -0
  31. package/dist/src/mocks/duplex.d.ts.map +1 -0
  32. package/dist/src/mocks/duplex.js +9 -0
  33. package/dist/src/mocks/duplex.js.map +1 -0
  34. package/dist/src/mocks/index.d.ts +13 -0
  35. package/dist/src/mocks/index.d.ts.map +1 -0
  36. package/dist/src/mocks/index.js +11 -0
  37. package/dist/src/mocks/index.js.map +1 -0
  38. package/dist/src/mocks/metrics.d.ts +3 -0
  39. package/dist/src/mocks/metrics.d.ts.map +1 -0
  40. package/dist/src/mocks/metrics.js +115 -0
  41. package/dist/src/mocks/metrics.js.map +1 -0
  42. package/dist/src/mocks/multiaddr-connection.d.ts +17 -0
  43. package/dist/src/mocks/multiaddr-connection.d.ts.map +1 -0
  44. package/dist/src/mocks/multiaddr-connection.js +60 -0
  45. package/dist/src/mocks/multiaddr-connection.js.map +1 -0
  46. package/dist/src/mocks/muxer.d.ts +36 -0
  47. package/dist/src/mocks/muxer.d.ts.map +1 -0
  48. package/dist/src/mocks/muxer.js +213 -0
  49. package/dist/src/mocks/muxer.js.map +1 -0
  50. package/dist/src/mocks/peer-discovery.d.ts +22 -0
  51. package/dist/src/mocks/peer-discovery.d.ts.map +1 -0
  52. package/dist/src/mocks/peer-discovery.js +47 -0
  53. package/dist/src/mocks/peer-discovery.js.map +1 -0
  54. package/dist/src/mocks/registrar.d.ts +18 -0
  55. package/dist/src/mocks/registrar.d.ts.map +1 -0
  56. package/dist/src/mocks/registrar.js +66 -0
  57. package/dist/src/mocks/registrar.js.map +1 -0
  58. package/dist/src/mocks/upgrader.d.ts +10 -0
  59. package/dist/src/mocks/upgrader.d.ts.map +1 -0
  60. package/dist/src/mocks/upgrader.js +31 -0
  61. package/dist/src/mocks/upgrader.js.map +1 -0
  62. package/dist/src/peer-discovery/index.d.ts +5 -0
  63. package/dist/src/peer-discovery/index.d.ts.map +1 -0
  64. package/dist/src/peer-discovery/index.js +66 -0
  65. package/dist/src/peer-discovery/index.js.map +1 -0
  66. package/dist/src/pubsub/api.d.ts +6 -0
  67. package/dist/src/pubsub/api.d.ts.map +1 -0
  68. package/dist/src/pubsub/api.js +87 -0
  69. package/dist/src/pubsub/api.js.map +1 -0
  70. package/dist/src/pubsub/connection-handlers.d.ts +6 -0
  71. package/dist/src/pubsub/connection-handlers.d.ts.map +1 -0
  72. package/dist/src/pubsub/connection-handlers.js +329 -0
  73. package/dist/src/pubsub/connection-handlers.js.map +1 -0
  74. package/dist/src/pubsub/emit-self.d.ts +6 -0
  75. package/dist/src/pubsub/emit-self.d.ts.map +1 -0
  76. package/dist/src/pubsub/emit-self.js +80 -0
  77. package/dist/src/pubsub/emit-self.js.map +1 -0
  78. package/dist/src/pubsub/index.d.ts +18 -0
  79. package/dist/src/pubsub/index.d.ts.map +1 -0
  80. package/dist/src/pubsub/index.js +17 -0
  81. package/dist/src/pubsub/index.js.map +1 -0
  82. package/dist/src/pubsub/messages.d.ts +6 -0
  83. package/dist/src/pubsub/messages.d.ts.map +1 -0
  84. package/dist/src/pubsub/messages.js +48 -0
  85. package/dist/src/pubsub/messages.js.map +1 -0
  86. package/dist/src/pubsub/multiple-nodes.d.ts +6 -0
  87. package/dist/src/pubsub/multiple-nodes.d.ts.map +1 -0
  88. package/dist/src/pubsub/multiple-nodes.js +350 -0
  89. package/dist/src/pubsub/multiple-nodes.js.map +1 -0
  90. package/dist/src/pubsub/two-nodes.d.ts +6 -0
  91. package/dist/src/pubsub/two-nodes.d.ts.map +1 -0
  92. package/dist/src/pubsub/two-nodes.js +217 -0
  93. package/dist/src/pubsub/two-nodes.js.map +1 -0
  94. package/dist/src/pubsub/utils.d.ts +6 -0
  95. package/dist/src/pubsub/utils.d.ts.map +1 -0
  96. package/dist/src/pubsub/utils.js +22 -0
  97. package/dist/src/pubsub/utils.js.map +1 -0
  98. package/dist/src/stream-muxer/base-test.d.ts +5 -0
  99. package/dist/src/stream-muxer/base-test.d.ts.map +1 -0
  100. package/dist/src/stream-muxer/base-test.js +153 -0
  101. package/dist/src/stream-muxer/base-test.js.map +1 -0
  102. package/dist/src/stream-muxer/close-test.d.ts +5 -0
  103. package/dist/src/stream-muxer/close-test.d.ts.map +1 -0
  104. package/dist/src/stream-muxer/close-test.js +357 -0
  105. package/dist/src/stream-muxer/close-test.js.map +1 -0
  106. package/dist/src/stream-muxer/fixtures/pb/message.d.ts +13 -0
  107. package/dist/src/stream-muxer/fixtures/pb/message.d.ts.map +1 -0
  108. package/dist/src/stream-muxer/fixtures/pb/message.js +67 -0
  109. package/dist/src/stream-muxer/fixtures/pb/message.js.map +1 -0
  110. package/dist/src/stream-muxer/index.d.ts +5 -0
  111. package/dist/src/stream-muxer/index.d.ts.map +1 -0
  112. package/dist/src/stream-muxer/index.js +13 -0
  113. package/dist/src/stream-muxer/index.js.map +1 -0
  114. package/dist/src/stream-muxer/mega-stress-test.d.ts +5 -0
  115. package/dist/src/stream-muxer/mega-stress-test.d.ts.map +1 -0
  116. package/dist/src/stream-muxer/mega-stress-test.js +11 -0
  117. package/dist/src/stream-muxer/mega-stress-test.js.map +1 -0
  118. package/dist/src/stream-muxer/spawner.d.ts +4 -0
  119. package/dist/src/stream-muxer/spawner.d.ts.map +1 -0
  120. package/dist/src/stream-muxer/spawner.js +37 -0
  121. package/dist/src/stream-muxer/spawner.js.map +1 -0
  122. package/dist/src/stream-muxer/stress-test.d.ts +5 -0
  123. package/dist/src/stream-muxer/stress-test.d.ts.map +1 -0
  124. package/dist/src/stream-muxer/stress-test.js +23 -0
  125. package/dist/src/stream-muxer/stress-test.js.map +1 -0
  126. package/dist/src/transport/dial-test.d.ts +5 -0
  127. package/dist/src/transport/dial-test.d.ts.map +1 -0
  128. package/dist/src/transport/dial-test.js +98 -0
  129. package/dist/src/transport/dial-test.js.map +1 -0
  130. package/dist/src/transport/filter-test.d.ts +5 -0
  131. package/dist/src/transport/filter-test.d.ts.map +1 -0
  132. package/dist/src/transport/filter-test.js +18 -0
  133. package/dist/src/transport/filter-test.js.map +1 -0
  134. package/dist/src/transport/index.d.ts +15 -0
  135. package/dist/src/transport/index.d.ts.map +1 -0
  136. package/dist/src/transport/index.js +11 -0
  137. package/dist/src/transport/index.js.map +1 -0
  138. package/dist/src/transport/listen-test.d.ts +5 -0
  139. package/dist/src/transport/listen-test.d.ts.map +1 -0
  140. package/dist/src/transport/listen-test.js +152 -0
  141. package/dist/src/transport/listen-test.js.map +1 -0
  142. package/package.json +73 -3
  143. package/src/connection/index.ts +182 -0
  144. package/src/connection-encryption/index.ts +97 -0
  145. package/src/connection-encryption/utils/index.ts +24 -0
  146. package/src/mocks/connection-encrypter.ts +113 -0
  147. package/src/mocks/connection-gater.ts +18 -0
  148. package/src/mocks/connection-manager.ts +211 -0
  149. package/src/mocks/connection.ts +224 -0
  150. package/src/mocks/duplex.ts +10 -0
  151. package/src/mocks/index.ts +12 -0
  152. package/src/mocks/metrics.ts +162 -0
  153. package/src/mocks/multiaddr-connection.ts +76 -0
  154. package/src/mocks/muxer.ts +303 -0
  155. package/src/mocks/peer-discovery.ts +60 -0
  156. package/src/mocks/registrar.ts +88 -0
  157. package/src/mocks/upgrader.ts +49 -0
  158. package/src/peer-discovery/index.ts +90 -0
  159. package/src/pubsub/api.ts +114 -0
  160. package/src/pubsub/connection-handlers.ts +413 -0
  161. package/src/pubsub/emit-self.ts +99 -0
  162. package/src/pubsub/index.ts +34 -0
  163. package/src/pubsub/messages.ts +59 -0
  164. package/src/pubsub/multiple-nodes.ts +440 -0
  165. package/src/pubsub/two-nodes.ts +273 -0
  166. package/src/pubsub/utils.ts +29 -0
  167. package/src/stream-muxer/base-test.ts +196 -0
  168. package/src/stream-muxer/close-test.ts +442 -0
  169. package/src/stream-muxer/fixtures/pb/message.proto +7 -0
  170. package/src/stream-muxer/fixtures/pb/message.ts +87 -0
  171. package/src/stream-muxer/index.ts +15 -0
  172. package/src/stream-muxer/mega-stress-test.ts +14 -0
  173. package/src/stream-muxer/spawner.ts +55 -0
  174. package/src/stream-muxer/stress-test.ts +27 -0
  175. package/src/transport/dial-test.ts +124 -0
  176. package/src/transport/filter-test.ts +25 -0
  177. package/src/transport/index.ts +25 -0
  178. package/src/transport/listen-test.ts +191 -0
@@ -0,0 +1,211 @@
1
+ import { CodeError } from '@libp2p/interface/errors'
2
+ import { isPeerId, type PeerId } from '@libp2p/interface/peer-id'
3
+ import { PeerMap } from '@libp2p/peer-collections'
4
+ import { peerIdFromString } from '@libp2p/peer-id'
5
+ import { isMultiaddr, type Multiaddr } from '@multiformats/multiaddr'
6
+ import { connectionPair } from './connection.js'
7
+ import type { Libp2pEvents, PendingDial } from '@libp2p/interface'
8
+ import type { Connection } from '@libp2p/interface/connection'
9
+ import type { EventEmitter } from '@libp2p/interface/events'
10
+ import type { PubSub } from '@libp2p/interface/pubsub'
11
+ import type { Startable } from '@libp2p/interface/startable'
12
+ import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager'
13
+ import type { Registrar } from '@libp2p/interface-internal/registrar'
14
+
15
+ export interface MockNetworkComponents {
16
+ peerId: PeerId
17
+ registrar: Registrar
18
+ connectionManager: ConnectionManager
19
+ events: EventEmitter<Libp2pEvents>
20
+ pubsub?: PubSub
21
+ }
22
+
23
+ class MockNetwork {
24
+ private components: MockNetworkComponents[] = []
25
+
26
+ addNode (components: MockNetworkComponents): void {
27
+ this.components.push(components)
28
+ }
29
+
30
+ getNode (peerId: PeerId | Multiaddr []): MockNetworkComponents {
31
+ if (Array.isArray(peerId) && peerId.length > 0) {
32
+ peerId = peerIdFromString(peerId[0].getPeerId() ?? '')
33
+ } else if (isPeerId(peerId)) {
34
+ for (const components of this.components) {
35
+ if (peerId.equals(components.peerId)) {
36
+ return components
37
+ }
38
+ }
39
+ }
40
+
41
+ throw new CodeError('Peer not found', 'ERR_PEER_NOT_FOUND')
42
+ }
43
+
44
+ reset (): void {
45
+ this.components = []
46
+ }
47
+ }
48
+
49
+ export const mockNetwork = new MockNetwork()
50
+
51
+ export interface MockConnectionManagerComponents {
52
+ peerId: PeerId
53
+ registrar: Registrar
54
+ events: EventEmitter<Libp2pEvents>
55
+ }
56
+
57
+ class MockConnectionManager implements ConnectionManager, Startable {
58
+ private connections: Connection[] = []
59
+ private readonly components: MockConnectionManagerComponents
60
+ private started = false
61
+
62
+ constructor (components: MockConnectionManagerComponents) {
63
+ this.components = components
64
+ }
65
+
66
+ isStarted (): boolean {
67
+ return this.started
68
+ }
69
+
70
+ async start (): Promise<void> {
71
+ this.started = true
72
+ }
73
+
74
+ async stop (): Promise<void> {
75
+ for (const connection of this.connections) {
76
+ await this.closeConnections(connection.remotePeer)
77
+ }
78
+
79
+ this.started = false
80
+ }
81
+
82
+ getConnections (peerId?: PeerId): Connection[] {
83
+ if (peerId != null) {
84
+ return this.connections
85
+ .filter(c => c.remotePeer.toString() === peerId.toString())
86
+ }
87
+
88
+ return this.connections
89
+ }
90
+
91
+ getConnectionsMap (): PeerMap<Connection[]> {
92
+ const map = new PeerMap<Connection[]>()
93
+
94
+ for (const conn of this.connections) {
95
+ const conns: Connection[] = map.get(conn.remotePeer) ?? []
96
+ conns.push(conn)
97
+
98
+ map.set(conn.remotePeer, conns)
99
+ }
100
+
101
+ return map
102
+ }
103
+
104
+ async openConnection (peerId: PeerId | Multiaddr | Multiaddr[]): Promise<Connection> {
105
+ if (this.components == null) {
106
+ throw new CodeError('Not initialized', 'ERR_NOT_INITIALIZED')
107
+ }
108
+
109
+ if (isMultiaddr(peerId)) {
110
+ throw new CodeError('Dialing multiaddrs not supported', 'ERR_NOT_SUPPORTED')
111
+ }
112
+
113
+ let existingConnections: Connection[] = []
114
+
115
+ if (Array.isArray(peerId) && peerId.length > 0) {
116
+ existingConnections = this.getConnections(peerIdFromString(peerId[0].getPeerId() ?? ''))
117
+ } else if (isPeerId(peerId)) {
118
+ existingConnections = this.getConnections(peerId)
119
+ }
120
+
121
+ if (existingConnections.length > 0) {
122
+ return existingConnections[0]
123
+ }
124
+
125
+ const componentsB = mockNetwork.getNode(peerId)
126
+
127
+ const [aToB, bToA] = connectionPair(this.components, componentsB)
128
+
129
+ // track connections
130
+ this.connections.push(aToB)
131
+ ;(componentsB.connectionManager as MockConnectionManager).connections.push(bToA)
132
+
133
+ this.components.events.safeDispatchEvent('connection:open', {
134
+ detail: aToB
135
+ })
136
+
137
+ for (const protocol of this.components.registrar.getProtocols()) {
138
+ for (const topology of this.components.registrar.getTopologies(protocol)) {
139
+ topology.onConnect?.(componentsB.peerId, aToB)
140
+ }
141
+ }
142
+
143
+ this.components.events.safeDispatchEvent('peer:connect', { detail: componentsB.peerId })
144
+
145
+ componentsB.events.safeDispatchEvent('connection:open', {
146
+ detail: bToA
147
+ })
148
+
149
+ for (const protocol of componentsB.registrar.getProtocols()) {
150
+ for (const topology of componentsB.registrar.getTopologies(protocol)) {
151
+ topology.onConnect?.(this.components.peerId, bToA)
152
+ }
153
+ }
154
+
155
+ componentsB.events.safeDispatchEvent('peer:connect', { detail: this.components.peerId })
156
+
157
+ return aToB
158
+ }
159
+
160
+ async closeConnections (peerId: PeerId): Promise<void> {
161
+ if (this.components == null) {
162
+ throw new CodeError('Not initialized', 'ERR_NOT_INITIALIZED')
163
+ }
164
+
165
+ const connections = this.getConnections(peerId)
166
+
167
+ if (connections.length === 0) {
168
+ return
169
+ }
170
+
171
+ const componentsB = mockNetwork.getNode(peerId)
172
+
173
+ for (const protocol of this.components.registrar.getProtocols()) {
174
+ this.components.registrar.getTopologies(protocol).forEach(topology => {
175
+ topology.onDisconnect?.(componentsB.peerId)
176
+ })
177
+ }
178
+
179
+ for (const conn of connections) {
180
+ await conn.close()
181
+ }
182
+
183
+ this.connections = this.connections.filter(c => !c.remotePeer.equals(peerId))
184
+
185
+ if (this.connections.filter(c => !c.remotePeer.equals(peerId)).length === 0) {
186
+ componentsB.events.safeDispatchEvent('peer:disconnect', { detail: peerId })
187
+ }
188
+
189
+ await componentsB.connectionManager?.closeConnections(this.components.peerId)
190
+
191
+ if (componentsB.connectionManager?.getConnectionsMap().get(this.components.peerId) == null) {
192
+ componentsB.events.safeDispatchEvent('peer:disconnect', { detail: this.components.peerId })
193
+ }
194
+ }
195
+
196
+ async acceptIncomingConnection (): Promise<boolean> {
197
+ return true
198
+ }
199
+
200
+ afterUpgradeInbound (): void {
201
+
202
+ }
203
+
204
+ getDialQueue (): PendingDial[] {
205
+ return []
206
+ }
207
+ }
208
+
209
+ export function mockConnectionManager (components: MockConnectionManagerComponents): ConnectionManager {
210
+ return new MockConnectionManager(components)
211
+ }
@@ -0,0 +1,224 @@
1
+ import { CodeError } from '@libp2p/interface/errors'
2
+ import { logger } from '@libp2p/logger'
3
+ import * as mss from '@libp2p/multistream-select'
4
+ import { peerIdFromString } from '@libp2p/peer-id'
5
+ import { duplexPair } from 'it-pair/duplex'
6
+ import { pipe } from 'it-pipe'
7
+ import { mockMultiaddrConnection } from './multiaddr-connection.js'
8
+ import { mockMuxer } from './muxer.js'
9
+ import { mockRegistrar } from './registrar.js'
10
+ import type { AbortOptions } from '@libp2p/interface'
11
+ import type { MultiaddrConnection, Connection, Stream, Direction, ConnectionTimeline, ConnectionStatus } from '@libp2p/interface/connection'
12
+ import type { PeerId } from '@libp2p/interface/peer-id'
13
+ import type { StreamMuxer, StreamMuxerFactory } from '@libp2p/interface/stream-muxer'
14
+ import type { Registrar } from '@libp2p/interface-internal/registrar'
15
+ import type { Multiaddr } from '@multiformats/multiaddr'
16
+ import type { Duplex, Source } from 'it-stream-types'
17
+ import type { Uint8ArrayList } from 'uint8arraylist'
18
+
19
+ const log = logger('libp2p:mock-connection')
20
+
21
+ export interface MockConnectionOptions {
22
+ direction?: Direction
23
+ registrar?: Registrar
24
+ muxerFactory?: StreamMuxerFactory
25
+ }
26
+
27
+ interface MockConnectionInit {
28
+ remoteAddr: Multiaddr
29
+ remotePeer: PeerId
30
+ direction: Direction
31
+ maConn: MultiaddrConnection
32
+ muxer: StreamMuxer
33
+ }
34
+
35
+ class MockConnection implements Connection {
36
+ public id: string
37
+ public remoteAddr: Multiaddr
38
+ public remotePeer: PeerId
39
+ public direction: Direction
40
+ public timeline: ConnectionTimeline
41
+ public multiplexer?: string
42
+ public encryption?: string
43
+ public status: ConnectionStatus
44
+ public streams: Stream[]
45
+ public tags: string[]
46
+
47
+ private readonly muxer: StreamMuxer
48
+ private readonly maConn: MultiaddrConnection
49
+
50
+ constructor (init: MockConnectionInit) {
51
+ const { remoteAddr, remotePeer, direction, maConn, muxer } = init
52
+
53
+ this.id = `mock-connection-${Math.random()}`
54
+ this.remoteAddr = remoteAddr
55
+ this.remotePeer = remotePeer
56
+ this.direction = direction
57
+ this.status = 'open'
58
+ this.direction = direction
59
+ this.timeline = maConn.timeline
60
+ this.multiplexer = 'test-multiplexer'
61
+ this.encryption = 'yes-yes-very-secure'
62
+ this.streams = []
63
+ this.tags = []
64
+ this.muxer = muxer
65
+ this.maConn = maConn
66
+ }
67
+
68
+ async newStream (protocols: string | string[], options?: AbortOptions): Promise<Stream> {
69
+ if (!Array.isArray(protocols)) {
70
+ protocols = [protocols]
71
+ }
72
+
73
+ if (protocols.length === 0) {
74
+ throw new Error('protocols must have a length')
75
+ }
76
+
77
+ if (this.status !== 'open') {
78
+ throw new CodeError('connection must be open to create streams', 'ERR_CONNECTION_CLOSED')
79
+ }
80
+
81
+ const id = `${Math.random()}`
82
+ const stream = await this.muxer.newStream(id)
83
+ const result = await mss.select(stream, protocols, options)
84
+
85
+ stream.protocol = result.protocol
86
+ stream.direction = 'outbound'
87
+ stream.sink = result.stream.sink
88
+ stream.source = result.stream.source
89
+
90
+ this.streams.push(stream)
91
+
92
+ return stream
93
+ }
94
+
95
+ addStream (stream: Stream): void {
96
+ this.streams.push(stream)
97
+ }
98
+
99
+ removeStream (id: string): void {
100
+ this.streams = this.streams.filter(stream => stream.id !== id)
101
+ }
102
+
103
+ async close (options?: AbortOptions): Promise<void> {
104
+ this.status = 'closing'
105
+ await Promise.all(
106
+ this.streams.map(async s => s.close(options))
107
+ )
108
+ await this.maConn.close()
109
+ this.status = 'closed'
110
+ this.timeline.close = Date.now()
111
+ }
112
+
113
+ abort (err: Error): void {
114
+ this.status = 'closing'
115
+ this.streams.forEach(s => {
116
+ s.abort(err)
117
+ })
118
+ this.maConn.abort(err)
119
+ this.status = 'closed'
120
+ this.timeline.close = Date.now()
121
+ }
122
+ }
123
+
124
+ export function mockConnection (maConn: MultiaddrConnection, opts: MockConnectionOptions = {}): Connection {
125
+ const remoteAddr = maConn.remoteAddr
126
+ const remotePeerIdStr = remoteAddr.getPeerId() ?? '12D3KooWCrhmFM1BCPGBkNzbPfDk4cjYmtAYSpZwUBC69Qg2kZyq'
127
+
128
+ if (remotePeerIdStr == null) {
129
+ throw new Error('Remote multiaddr must contain a peer id')
130
+ }
131
+
132
+ const remotePeer = peerIdFromString(remotePeerIdStr)
133
+ const direction = opts.direction ?? 'inbound'
134
+ const registrar = opts.registrar ?? mockRegistrar()
135
+ const muxerFactory = opts.muxerFactory ?? mockMuxer()
136
+
137
+ const muxer = muxerFactory.createStreamMuxer({
138
+ direction,
139
+ onIncomingStream: (muxedStream) => {
140
+ try {
141
+ mss.handle(muxedStream, registrar.getProtocols())
142
+ .then(({ stream, protocol }) => {
143
+ log('%s: incoming stream opened on %s', direction, protocol)
144
+ muxedStream.protocol = protocol
145
+ muxedStream.sink = stream.sink
146
+ muxedStream.source = stream.source
147
+
148
+ connection.addStream(muxedStream)
149
+ const { handler } = registrar.getHandler(protocol)
150
+
151
+ handler({ connection, stream: muxedStream })
152
+ }).catch(err => {
153
+ log.error(err)
154
+ })
155
+ } catch (err: any) {
156
+ log.error(err)
157
+ }
158
+ },
159
+ onStreamEnd: (muxedStream) => {
160
+ connection.removeStream(muxedStream.id)
161
+ }
162
+ })
163
+
164
+ void pipe(
165
+ maConn, muxer, maConn
166
+ )
167
+
168
+ const connection = new MockConnection({
169
+ remoteAddr,
170
+ remotePeer,
171
+ direction,
172
+ maConn,
173
+ muxer
174
+ })
175
+
176
+ return connection
177
+ }
178
+
179
+ export function mockStream (stream: Duplex<AsyncGenerator<Uint8ArrayList>, Source<Uint8ArrayList | Uint8Array>, Promise<void>>): Stream {
180
+ return {
181
+ ...stream,
182
+ close: async () => {},
183
+ closeRead: async () => {},
184
+ closeWrite: async () => {},
185
+ abort: () => {},
186
+ direction: 'outbound',
187
+ protocol: '/foo/1.0.0',
188
+ timeline: {
189
+ open: Date.now()
190
+ },
191
+ metadata: {},
192
+ id: `stream-${Date.now()}`,
193
+ status: 'open',
194
+ readStatus: 'ready',
195
+ writeStatus: 'ready'
196
+ }
197
+ }
198
+
199
+ export interface Peer {
200
+ peerId: PeerId
201
+ registrar: Registrar
202
+ }
203
+
204
+ export function multiaddrConnectionPair (a: { peerId: PeerId, registrar: Registrar }, b: { peerId: PeerId, registrar: Registrar }): [ MultiaddrConnection, MultiaddrConnection ] {
205
+ const [peerBtoPeerA, peerAtoPeerB] = duplexPair<Uint8Array>()
206
+
207
+ return [
208
+ mockMultiaddrConnection(peerAtoPeerB, b.peerId),
209
+ mockMultiaddrConnection(peerBtoPeerA, a.peerId)
210
+ ]
211
+ }
212
+
213
+ export function connectionPair (a: { peerId: PeerId, registrar: Registrar }, b: { peerId: PeerId, registrar: Registrar }): [ Connection, Connection ] {
214
+ const [peerBtoPeerA, peerAtoPeerB] = multiaddrConnectionPair(a, b)
215
+
216
+ return [
217
+ mockConnection(peerBtoPeerA, {
218
+ registrar: a.registrar
219
+ }),
220
+ mockConnection(peerAtoPeerB, {
221
+ registrar: b.registrar
222
+ })
223
+ ]
224
+ }
@@ -0,0 +1,10 @@
1
+ import type { Duplex, Source } from 'it-stream-types'
2
+
3
+ export function mockDuplex (): Duplex<AsyncGenerator<Uint8Array>, Source<Uint8Array>, Promise<void>> {
4
+ return {
5
+ source: (async function * () {
6
+ yield * []
7
+ }()),
8
+ sink: async () => {}
9
+ }
10
+ }
@@ -0,0 +1,12 @@
1
+ export { mockConnectionEncrypter } from './connection-encrypter.js'
2
+ export { mockConnectionGater } from './connection-gater.js'
3
+ export { mockConnectionManager, mockNetwork } from './connection-manager.js'
4
+ export { mockConnection, mockStream, connectionPair } from './connection.js'
5
+ export { mockMultiaddrConnection, mockMultiaddrConnPair } from './multiaddr-connection.js'
6
+ export { mockMuxer } from './muxer.js'
7
+ export { mockRegistrar } from './registrar.js'
8
+ export { mockUpgrader } from './upgrader.js'
9
+ export { mockDuplex } from './duplex.js'
10
+ export { mockMetrics } from './metrics.js'
11
+ export type { MockUpgraderInit } from './upgrader.js'
12
+ export type { MockNetworkComponents } from './connection-manager.js'
@@ -0,0 +1,162 @@
1
+ import type { MultiaddrConnection, Stream, Connection } from '@libp2p/interface/connection'
2
+ import type { Metric, MetricGroup, StopTimer, Metrics, CalculatedMetricOptions, MetricOptions } from '@libp2p/interface/metrics'
3
+
4
+ class DefaultMetric implements Metric {
5
+ public value: number = 0
6
+
7
+ update (value: number): void {
8
+ this.value = value
9
+ }
10
+
11
+ increment (value: number = 1): void {
12
+ this.value += value
13
+ }
14
+
15
+ decrement (value: number = 1): void {
16
+ this.value -= value
17
+ }
18
+
19
+ reset (): void {
20
+ this.value = 0
21
+ }
22
+
23
+ timer (): StopTimer {
24
+ const start = Date.now()
25
+
26
+ return () => {
27
+ this.value = Date.now() - start
28
+ }
29
+ }
30
+ }
31
+
32
+ class DefaultGroupMetric implements MetricGroup {
33
+ public values: Record<string, number> = {}
34
+
35
+ update (values: Record<string, number>): void {
36
+ Object.entries(values).forEach(([key, value]) => {
37
+ this.values[key] = value
38
+ })
39
+ }
40
+
41
+ increment (values: Record<string, number | unknown>): void {
42
+ Object.entries(values).forEach(([key, value]) => {
43
+ this.values[key] = this.values[key] ?? 0
44
+ const inc = typeof value === 'number' ? value : 1
45
+
46
+ this.values[key] += Number(inc)
47
+ })
48
+ }
49
+
50
+ decrement (values: Record<string, number | unknown>): void {
51
+ Object.entries(values).forEach(([key, value]) => {
52
+ this.values[key] = this.values[key] ?? 0
53
+ const dec = typeof value === 'number' ? value : 1
54
+
55
+ this.values[key] -= Number(dec)
56
+ })
57
+ }
58
+
59
+ reset (): void {
60
+ this.values = {}
61
+ }
62
+
63
+ timer (key: string): StopTimer {
64
+ const start = Date.now()
65
+
66
+ return () => {
67
+ this.values[key] = Date.now() - start
68
+ }
69
+ }
70
+ }
71
+
72
+ class MockMetrics implements Metrics {
73
+ public metrics = new Map<string, any>()
74
+
75
+ trackMultiaddrConnection (maConn: MultiaddrConnection): void {
76
+
77
+ }
78
+
79
+ trackProtocolStream (stream: Stream, connection: Connection): void {
80
+
81
+ }
82
+
83
+ registerMetric (name: string, opts: CalculatedMetricOptions): void
84
+ registerMetric (name: string, opts?: MetricOptions): Metric
85
+ registerMetric (name: string, opts: any): any {
86
+ if (name == null ?? name.trim() === '') {
87
+ throw new Error('Metric name is required')
88
+ }
89
+
90
+ if (opts?.calculate != null) {
91
+ // calculated metric
92
+ this.metrics.set(name, opts.calculate)
93
+ return
94
+ }
95
+
96
+ const metric = new DefaultMetric()
97
+ this.metrics.set(name, metric)
98
+
99
+ return metric
100
+ }
101
+
102
+ registerCounter (name: string, opts: CalculatedMetricOptions): void
103
+ registerCounter (name: string, opts?: MetricOptions): Metric
104
+ registerCounter (name: string, opts: any): any {
105
+ if (name == null ?? name.trim() === '') {
106
+ throw new Error('Metric name is required')
107
+ }
108
+
109
+ if (opts?.calculate != null) {
110
+ // calculated metric
111
+ this.metrics.set(name, opts.calculate)
112
+ return
113
+ }
114
+
115
+ const metric = new DefaultMetric()
116
+ this.metrics.set(name, metric)
117
+
118
+ return metric
119
+ }
120
+
121
+ registerMetricGroup (name: string, opts: CalculatedMetricOptions<Record<string, number>>): void
122
+ registerMetricGroup (name: string, opts?: MetricOptions): MetricGroup
123
+ registerMetricGroup (name: string, opts: any): any {
124
+ if (name == null ?? name.trim() === '') {
125
+ throw new Error('Metric name is required')
126
+ }
127
+
128
+ if (opts?.calculate != null) {
129
+ // calculated metric
130
+ this.metrics.set(name, opts.calculate)
131
+ return
132
+ }
133
+
134
+ const metric = new DefaultGroupMetric()
135
+ this.metrics.set(name, metric)
136
+
137
+ return metric
138
+ }
139
+
140
+ registerCounterGroup (name: string, opts: CalculatedMetricOptions<Record<string, number>>): void
141
+ registerCounterGroup (name: string, opts?: MetricOptions): MetricGroup
142
+ registerCounterGroup (name: string, opts: any): any {
143
+ if (name == null ?? name.trim() === '') {
144
+ throw new Error('Metric name is required')
145
+ }
146
+
147
+ if (opts?.calculate != null) {
148
+ // calculated metric
149
+ this.metrics.set(name, opts.calculate)
150
+ return
151
+ }
152
+
153
+ const metric = new DefaultGroupMetric()
154
+ this.metrics.set(name, metric)
155
+
156
+ return metric
157
+ }
158
+ }
159
+
160
+ export function mockMetrics (): () => Metrics {
161
+ return () => new MockMetrics()
162
+ }
@@ -0,0 +1,76 @@
1
+ import { multiaddr } from '@multiformats/multiaddr'
2
+ import { abortableSource } from 'abortable-iterator'
3
+ import { duplexPair } from 'it-pair/duplex'
4
+ import type { MultiaddrConnection } from '@libp2p/interface/connection'
5
+ import type { PeerId } from '@libp2p/interface/peer-id'
6
+ import type { Multiaddr } from '@multiformats/multiaddr'
7
+ import type { Duplex } from 'it-stream-types'
8
+
9
+ export function mockMultiaddrConnection (source: Duplex<AsyncGenerator<Uint8Array>> & Partial<MultiaddrConnection>, peerId: PeerId): MultiaddrConnection {
10
+ const maConn: MultiaddrConnection = {
11
+ async close () {
12
+
13
+ },
14
+ abort: () => {},
15
+ timeline: {
16
+ open: Date.now()
17
+ },
18
+ remoteAddr: multiaddr(`/ip4/127.0.0.1/tcp/4001/p2p/${peerId.toString()}`),
19
+ ...source
20
+ }
21
+
22
+ return maConn
23
+ }
24
+
25
+ export interface MockMultiaddrConnPairOptions {
26
+ addrs: Multiaddr[]
27
+ remotePeer: PeerId
28
+ }
29
+
30
+ /**
31
+ * Returns both sides of a mocked MultiaddrConnection
32
+ */
33
+ export function mockMultiaddrConnPair (opts: MockMultiaddrConnPairOptions): { inbound: MultiaddrConnection, outbound: MultiaddrConnection } {
34
+ const { addrs, remotePeer } = opts
35
+ const controller = new AbortController()
36
+ const [localAddr, remoteAddr] = addrs
37
+ const [inboundStream, outboundStream] = duplexPair<Uint8Array>()
38
+
39
+ const outbound: MultiaddrConnection = {
40
+ ...outboundStream,
41
+ remoteAddr: remoteAddr.toString().includes(`/p2p/${remotePeer.toString()}`) ? remoteAddr : remoteAddr.encapsulate(`/p2p/${remotePeer.toString()}`),
42
+ timeline: {
43
+ open: Date.now()
44
+ },
45
+ close: async () => {
46
+ outbound.timeline.close = Date.now()
47
+ controller.abort()
48
+ },
49
+ abort: (err: Error) => {
50
+ outbound.timeline.close = Date.now()
51
+ controller.abort(err)
52
+ }
53
+ }
54
+
55
+ const inbound: MultiaddrConnection = {
56
+ ...inboundStream,
57
+ remoteAddr: localAddr,
58
+ timeline: {
59
+ open: Date.now()
60
+ },
61
+ close: async () => {
62
+ inbound.timeline.close = Date.now()
63
+ controller.abort()
64
+ },
65
+ abort: (err: Error) => {
66
+ outbound.timeline.close = Date.now()
67
+ controller.abort(err)
68
+ }
69
+ }
70
+
71
+ // Make the sources abortable so we can close them easily
72
+ inbound.source = abortableSource(inbound.source, controller.signal)
73
+ outbound.source = abortableSource(outbound.source, controller.signal)
74
+
75
+ return { inbound, outbound }
76
+ }