@libp2p/interface-compliance-tests 3.0.7-ea8a0637 → 3.0.7-eabf6f36

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 (183) 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/index.d.ts.map +1 -1
  15. package/dist/src/is-valid-tick.d.ts.map +1 -1
  16. package/dist/src/is-valid-tick.js.map +1 -1
  17. package/dist/src/mocks/connection-encrypter.d.ts +3 -0
  18. package/dist/src/mocks/connection-encrypter.d.ts.map +1 -0
  19. package/dist/src/mocks/connection-encrypter.js +98 -0
  20. package/dist/src/mocks/connection-encrypter.js.map +1 -0
  21. package/dist/src/mocks/connection-gater.d.ts +3 -0
  22. package/dist/src/mocks/connection-gater.d.ts.map +1 -0
  23. package/dist/src/mocks/connection-gater.js +17 -0
  24. package/dist/src/mocks/connection-gater.js.map +1 -0
  25. package/dist/src/mocks/connection-manager.d.ts +29 -0
  26. package/dist/src/mocks/connection-manager.d.ts.map +1 -0
  27. package/dist/src/mocks/connection-manager.js +145 -0
  28. package/dist/src/mocks/connection-manager.js.map +1 -0
  29. package/dist/src/mocks/connection.d.ts +32 -0
  30. package/dist/src/mocks/connection.d.ts.map +1 -0
  31. package/dist/src/mocks/connection.js +167 -0
  32. package/dist/src/mocks/connection.js.map +1 -0
  33. package/dist/src/mocks/duplex.d.ts +3 -0
  34. package/dist/src/mocks/duplex.d.ts.map +1 -0
  35. package/dist/src/mocks/duplex.js +9 -0
  36. package/dist/src/mocks/duplex.js.map +1 -0
  37. package/dist/src/mocks/index.d.ts +13 -0
  38. package/dist/src/mocks/index.d.ts.map +1 -0
  39. package/dist/src/mocks/index.js +11 -0
  40. package/dist/src/mocks/index.js.map +1 -0
  41. package/dist/src/mocks/metrics.d.ts +3 -0
  42. package/dist/src/mocks/metrics.d.ts.map +1 -0
  43. package/dist/src/mocks/metrics.js +115 -0
  44. package/dist/src/mocks/metrics.js.map +1 -0
  45. package/dist/src/mocks/multiaddr-connection.d.ts +17 -0
  46. package/dist/src/mocks/multiaddr-connection.d.ts.map +1 -0
  47. package/dist/src/mocks/multiaddr-connection.js +60 -0
  48. package/dist/src/mocks/multiaddr-connection.js.map +1 -0
  49. package/dist/src/mocks/muxer.d.ts +36 -0
  50. package/dist/src/mocks/muxer.d.ts.map +1 -0
  51. package/dist/src/mocks/muxer.js +213 -0
  52. package/dist/src/mocks/muxer.js.map +1 -0
  53. package/dist/src/mocks/peer-discovery.d.ts +22 -0
  54. package/dist/src/mocks/peer-discovery.d.ts.map +1 -0
  55. package/dist/src/mocks/peer-discovery.js +47 -0
  56. package/dist/src/mocks/peer-discovery.js.map +1 -0
  57. package/dist/src/mocks/registrar.d.ts +18 -0
  58. package/dist/src/mocks/registrar.d.ts.map +1 -0
  59. package/dist/src/mocks/registrar.js +66 -0
  60. package/dist/src/mocks/registrar.js.map +1 -0
  61. package/dist/src/mocks/upgrader.d.ts +10 -0
  62. package/dist/src/mocks/upgrader.d.ts.map +1 -0
  63. package/dist/src/mocks/upgrader.js +31 -0
  64. package/dist/src/mocks/upgrader.js.map +1 -0
  65. package/dist/src/peer-discovery/index.d.ts +5 -0
  66. package/dist/src/peer-discovery/index.d.ts.map +1 -0
  67. package/dist/src/peer-discovery/index.js +66 -0
  68. package/dist/src/peer-discovery/index.js.map +1 -0
  69. package/dist/src/pubsub/api.d.ts +6 -0
  70. package/dist/src/pubsub/api.d.ts.map +1 -0
  71. package/dist/src/pubsub/api.js +87 -0
  72. package/dist/src/pubsub/api.js.map +1 -0
  73. package/dist/src/pubsub/connection-handlers.d.ts +6 -0
  74. package/dist/src/pubsub/connection-handlers.d.ts.map +1 -0
  75. package/dist/src/pubsub/connection-handlers.js +329 -0
  76. package/dist/src/pubsub/connection-handlers.js.map +1 -0
  77. package/dist/src/pubsub/emit-self.d.ts +6 -0
  78. package/dist/src/pubsub/emit-self.d.ts.map +1 -0
  79. package/dist/src/pubsub/emit-self.js +80 -0
  80. package/dist/src/pubsub/emit-self.js.map +1 -0
  81. package/dist/src/pubsub/index.d.ts +18 -0
  82. package/dist/src/pubsub/index.d.ts.map +1 -0
  83. package/dist/src/pubsub/index.js +17 -0
  84. package/dist/src/pubsub/index.js.map +1 -0
  85. package/dist/src/pubsub/messages.d.ts +6 -0
  86. package/dist/src/pubsub/messages.d.ts.map +1 -0
  87. package/dist/src/pubsub/messages.js +48 -0
  88. package/dist/src/pubsub/messages.js.map +1 -0
  89. package/dist/src/pubsub/multiple-nodes.d.ts +6 -0
  90. package/dist/src/pubsub/multiple-nodes.d.ts.map +1 -0
  91. package/dist/src/pubsub/multiple-nodes.js +350 -0
  92. package/dist/src/pubsub/multiple-nodes.js.map +1 -0
  93. package/dist/src/pubsub/two-nodes.d.ts +6 -0
  94. package/dist/src/pubsub/two-nodes.d.ts.map +1 -0
  95. package/dist/src/pubsub/two-nodes.js +217 -0
  96. package/dist/src/pubsub/two-nodes.js.map +1 -0
  97. package/dist/src/pubsub/utils.d.ts +6 -0
  98. package/dist/src/pubsub/utils.d.ts.map +1 -0
  99. package/dist/src/pubsub/utils.js +22 -0
  100. package/dist/src/pubsub/utils.js.map +1 -0
  101. package/dist/src/stream-muxer/base-test.d.ts +5 -0
  102. package/dist/src/stream-muxer/base-test.d.ts.map +1 -0
  103. package/dist/src/stream-muxer/base-test.js +153 -0
  104. package/dist/src/stream-muxer/base-test.js.map +1 -0
  105. package/dist/src/stream-muxer/close-test.d.ts +5 -0
  106. package/dist/src/stream-muxer/close-test.d.ts.map +1 -0
  107. package/dist/src/stream-muxer/close-test.js +357 -0
  108. package/dist/src/stream-muxer/close-test.js.map +1 -0
  109. package/dist/src/stream-muxer/fixtures/pb/message.d.ts +13 -0
  110. package/dist/src/stream-muxer/fixtures/pb/message.d.ts.map +1 -0
  111. package/dist/src/stream-muxer/fixtures/pb/message.js +67 -0
  112. package/dist/src/stream-muxer/fixtures/pb/message.js.map +1 -0
  113. package/dist/src/stream-muxer/index.d.ts +5 -0
  114. package/dist/src/stream-muxer/index.d.ts.map +1 -0
  115. package/dist/src/stream-muxer/index.js +13 -0
  116. package/dist/src/stream-muxer/index.js.map +1 -0
  117. package/dist/src/stream-muxer/mega-stress-test.d.ts +5 -0
  118. package/dist/src/stream-muxer/mega-stress-test.d.ts.map +1 -0
  119. package/dist/src/stream-muxer/mega-stress-test.js +11 -0
  120. package/dist/src/stream-muxer/mega-stress-test.js.map +1 -0
  121. package/dist/src/stream-muxer/spawner.d.ts +4 -0
  122. package/dist/src/stream-muxer/spawner.d.ts.map +1 -0
  123. package/dist/src/stream-muxer/spawner.js +37 -0
  124. package/dist/src/stream-muxer/spawner.js.map +1 -0
  125. package/dist/src/stream-muxer/stress-test.d.ts +5 -0
  126. package/dist/src/stream-muxer/stress-test.d.ts.map +1 -0
  127. package/dist/src/stream-muxer/stress-test.js +23 -0
  128. package/dist/src/stream-muxer/stress-test.js.map +1 -0
  129. package/dist/src/transport/dial-test.d.ts +5 -0
  130. package/dist/src/transport/dial-test.d.ts.map +1 -0
  131. package/dist/src/transport/dial-test.js +98 -0
  132. package/dist/src/transport/dial-test.js.map +1 -0
  133. package/dist/src/transport/filter-test.d.ts +5 -0
  134. package/dist/src/transport/filter-test.d.ts.map +1 -0
  135. package/dist/src/transport/filter-test.js +18 -0
  136. package/dist/src/transport/filter-test.js.map +1 -0
  137. package/dist/src/transport/index.d.ts +15 -0
  138. package/dist/src/transport/index.d.ts.map +1 -0
  139. package/dist/src/transport/index.js +11 -0
  140. package/dist/src/transport/index.js.map +1 -0
  141. package/dist/src/transport/listen-test.d.ts +5 -0
  142. package/dist/src/transport/listen-test.d.ts.map +1 -0
  143. package/dist/src/transport/listen-test.js +152 -0
  144. package/dist/src/transport/listen-test.js.map +1 -0
  145. package/package.json +72 -5
  146. package/src/connection/index.ts +182 -0
  147. package/src/connection-encryption/index.ts +97 -0
  148. package/src/connection-encryption/utils/index.ts +24 -0
  149. package/src/index.ts +0 -1
  150. package/src/is-valid-tick.ts +0 -1
  151. package/src/mocks/connection-encrypter.ts +113 -0
  152. package/src/mocks/connection-gater.ts +18 -0
  153. package/src/mocks/connection-manager.ts +211 -0
  154. package/src/mocks/connection.ts +226 -0
  155. package/src/mocks/duplex.ts +10 -0
  156. package/src/mocks/index.ts +12 -0
  157. package/src/mocks/metrics.ts +162 -0
  158. package/src/mocks/multiaddr-connection.ts +76 -0
  159. package/src/mocks/muxer.ts +303 -0
  160. package/src/mocks/peer-discovery.ts +60 -0
  161. package/src/mocks/registrar.ts +88 -0
  162. package/src/mocks/upgrader.ts +49 -0
  163. package/src/peer-discovery/index.ts +90 -0
  164. package/src/pubsub/api.ts +114 -0
  165. package/src/pubsub/connection-handlers.ts +413 -0
  166. package/src/pubsub/emit-self.ts +99 -0
  167. package/src/pubsub/index.ts +34 -0
  168. package/src/pubsub/messages.ts +59 -0
  169. package/src/pubsub/multiple-nodes.ts +440 -0
  170. package/src/pubsub/two-nodes.ts +273 -0
  171. package/src/pubsub/utils.ts +29 -0
  172. package/src/stream-muxer/base-test.ts +196 -0
  173. package/src/stream-muxer/close-test.ts +442 -0
  174. package/src/stream-muxer/fixtures/pb/message.proto +7 -0
  175. package/src/stream-muxer/fixtures/pb/message.ts +87 -0
  176. package/src/stream-muxer/index.ts +15 -0
  177. package/src/stream-muxer/mega-stress-test.ts +14 -0
  178. package/src/stream-muxer/spawner.ts +55 -0
  179. package/src/stream-muxer/stress-test.ts +27 -0
  180. package/src/transport/dial-test.ts +124 -0
  181. package/src/transport/filter-test.ts +25 -0
  182. package/src/transport/index.ts +25 -0
  183. package/src/transport/listen-test.ts +191 -0
@@ -0,0 +1,49 @@
1
+ import { mockConnection } from './connection.js'
2
+ import type { Libp2pEvents } from '@libp2p/interface'
3
+ import type { Connection, MultiaddrConnection } from '@libp2p/interface/connection'
4
+ import type { EventEmitter } from '@libp2p/interface/events'
5
+ import type { Upgrader, UpgraderOptions } from '@libp2p/interface/transport'
6
+ import type { Registrar } from '@libp2p/interface-internal/registrar'
7
+
8
+ export interface MockUpgraderInit {
9
+ registrar?: Registrar
10
+ events?: EventEmitter<Libp2pEvents>
11
+ }
12
+
13
+ class MockUpgrader implements Upgrader {
14
+ private readonly registrar?: Registrar
15
+ private readonly events?: EventEmitter<Libp2pEvents>
16
+
17
+ constructor (init: MockUpgraderInit) {
18
+ this.registrar = init.registrar
19
+ this.events = init.events
20
+ }
21
+
22
+ async upgradeOutbound (multiaddrConnection: MultiaddrConnection, opts: UpgraderOptions = {}): Promise<Connection> {
23
+ const connection = mockConnection(multiaddrConnection, {
24
+ direction: 'outbound',
25
+ registrar: this.registrar,
26
+ ...opts
27
+ })
28
+
29
+ this.events?.safeDispatchEvent('connection:open', { detail: connection })
30
+
31
+ return connection
32
+ }
33
+
34
+ async upgradeInbound (multiaddrConnection: MultiaddrConnection, opts: UpgraderOptions = {}): Promise<Connection> {
35
+ const connection = mockConnection(multiaddrConnection, {
36
+ direction: 'inbound',
37
+ registrar: this.registrar,
38
+ ...opts
39
+ })
40
+
41
+ this.events?.safeDispatchEvent('connection:open', { detail: connection })
42
+
43
+ return connection
44
+ }
45
+ }
46
+
47
+ export function mockUpgrader (init: MockUpgraderInit = {}): Upgrader {
48
+ return new MockUpgrader(init)
49
+ }
@@ -0,0 +1,90 @@
1
+ import { start, stop } from '@libp2p/interface/startable'
2
+ import { isMultiaddr } from '@multiformats/multiaddr'
3
+ import { expect } from 'aegir/chai'
4
+ import delay from 'delay'
5
+ import pDefer from 'p-defer'
6
+ import type { TestSetup } from '../index.js'
7
+ import type { PeerDiscovery } from '@libp2p/interface/peer-discovery'
8
+
9
+ export default (common: TestSetup<PeerDiscovery>): void => {
10
+ describe('interface-peer-discovery compliance tests', () => {
11
+ let discovery: PeerDiscovery
12
+
13
+ beforeEach(async () => {
14
+ discovery = await common.setup()
15
+ })
16
+
17
+ afterEach('ensure discovery was stopped', async () => {
18
+ await stop(discovery)
19
+
20
+ await common.teardown()
21
+ })
22
+
23
+ it('can start the service', async () => {
24
+ await start(discovery)
25
+ })
26
+
27
+ it('can start and stop the service', async () => {
28
+ await start(discovery)
29
+ await stop(discovery)
30
+ })
31
+
32
+ it('should not fail to stop the service if it was not started', async () => {
33
+ await stop(discovery)
34
+ })
35
+
36
+ it('should not fail to start the service if it is already started', async () => {
37
+ await start(discovery)
38
+ await start(discovery)
39
+ })
40
+
41
+ it('should emit a peer event after start', async () => {
42
+ const defer = pDefer()
43
+
44
+ discovery.addEventListener('peer', (evt) => {
45
+ const { id, multiaddrs } = evt.detail
46
+ expect(id).to.exist()
47
+ expect(id)
48
+ .to.have.property('type')
49
+ .that.is.oneOf(['RSA', 'Ed25519', 'secp256k1'])
50
+ expect(multiaddrs).to.exist()
51
+
52
+ multiaddrs.forEach((m) => expect(isMultiaddr(m)).to.eql(true))
53
+
54
+ defer.resolve()
55
+ })
56
+
57
+ await start(discovery)
58
+
59
+ await defer.promise
60
+ })
61
+
62
+ it('should not receive a peer event before start', async () => {
63
+ discovery.addEventListener('peer', () => {
64
+ throw new Error('should not receive a peer event before start')
65
+ })
66
+
67
+ await delay(2000)
68
+ })
69
+
70
+ it('should not receive a peer event after stop', async () => {
71
+ const deferStart = pDefer()
72
+
73
+ discovery.addEventListener('peer', () => {
74
+ deferStart.resolve()
75
+ })
76
+
77
+ await start(discovery)
78
+
79
+ await deferStart.promise
80
+
81
+ await stop(discovery)
82
+
83
+ discovery.addEventListener('peer', () => {
84
+ throw new Error('should not receive a peer event after stop')
85
+ })
86
+
87
+ await delay(2000)
88
+ })
89
+ })
90
+ }
@@ -0,0 +1,114 @@
1
+ import { isStartable, start, stop } from '@libp2p/interface/startable'
2
+ import { expect } from 'aegir/chai'
3
+ import delay from 'delay'
4
+ import pDefer from 'p-defer'
5
+ import pWaitFor from 'p-wait-for'
6
+ import sinon from 'sinon'
7
+ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
8
+ import { mockNetwork } from '../mocks/index.js'
9
+ import { createComponents } from './utils.js'
10
+ import type { PubSubArgs, PubSubComponents } from './index.js'
11
+ import type { TestSetup } from '../index.js'
12
+ import type { PubSub } from '@libp2p/interface/pubsub'
13
+
14
+ const topic = 'foo'
15
+ const data = uint8ArrayFromString('bar')
16
+
17
+ export default (common: TestSetup<PubSub, PubSubArgs>): void => {
18
+ describe('pubsub api', () => {
19
+ let pubsub: PubSub
20
+ let components: PubSubComponents
21
+
22
+ // Create pubsub router
23
+ beforeEach(async () => {
24
+ mockNetwork.reset()
25
+ components = await createComponents()
26
+
27
+ pubsub = components.pubsub = await common.setup({
28
+ components,
29
+ init: {
30
+ emitSelf: true
31
+ }
32
+ })
33
+ })
34
+
35
+ afterEach(async () => {
36
+ sinon.restore()
37
+ await stop(...Object.values(components))
38
+ await common.teardown()
39
+ mockNetwork.reset()
40
+ })
41
+
42
+ it('can start correctly', async () => {
43
+ if (!isStartable(pubsub)) {
44
+ return
45
+ }
46
+
47
+ sinon.spy(components.registrar, 'register')
48
+
49
+ await start(...Object.values(components))
50
+
51
+ expect(pubsub.isStarted()).to.equal(true)
52
+ expect(components.registrar.register).to.have.property('callCount', 1)
53
+ })
54
+
55
+ it('can stop correctly', async () => {
56
+ if (!isStartable(pubsub)) {
57
+ return
58
+ }
59
+
60
+ sinon.spy(components.registrar, 'unregister')
61
+
62
+ await start(...Object.values(components))
63
+ await stop(...Object.values(components))
64
+
65
+ expect(pubsub.isStarted()).to.equal(false)
66
+ expect(components.registrar.unregister).to.have.property('callCount', 1)
67
+ })
68
+
69
+ it('can subscribe and unsubscribe correctly', async () => {
70
+ const handler = (): void => {
71
+ throw new Error('a message should not be received')
72
+ }
73
+
74
+ await start(...Object.values(components))
75
+ pubsub.subscribe(topic)
76
+ pubsub.addEventListener('message', handler)
77
+
78
+ await pWaitFor(() => {
79
+ const topics = pubsub.getTopics()
80
+ return topics.length === 1 && topics[0] === topic
81
+ })
82
+
83
+ pubsub.removeEventListener('message', handler)
84
+ pubsub.unsubscribe(topic)
85
+
86
+ await pWaitFor(() => pubsub.getTopics().length === 0)
87
+
88
+ // Publish to guarantee the handler is not called
89
+ await pubsub.publish(topic, data)
90
+
91
+ // handlers are called async
92
+ await delay(100)
93
+
94
+ await stop(...Object.values(components))
95
+ })
96
+
97
+ it('can subscribe and publish correctly', async () => {
98
+ const defer = pDefer()
99
+
100
+ await start(...Object.values(components))
101
+
102
+ pubsub.subscribe(topic)
103
+ pubsub.addEventListener('message', (evt) => {
104
+ expect(evt).to.have.nested.property('detail.topic', topic)
105
+ expect(evt).to.have.deep.nested.property('detail.data', data)
106
+ defer.resolve()
107
+ })
108
+ await pubsub.publish(topic, data)
109
+ await defer.promise
110
+
111
+ await stop(...Object.values(components))
112
+ })
113
+ })
114
+ }
@@ -0,0 +1,413 @@
1
+ import { start, stop } from '@libp2p/interface/startable'
2
+ import { expect } from 'aegir/chai'
3
+ import pDefer from 'p-defer'
4
+ import { pEvent } from 'p-event'
5
+ import pWaitFor from 'p-wait-for'
6
+ import sinon from 'sinon'
7
+ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
8
+ import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
9
+ import { mockNetwork } from '../mocks/index.js'
10
+ import { createComponents } from './utils.js'
11
+ import type { PubSubArgs } from './index.js'
12
+ import type { TestSetup } from '../index.js'
13
+ import type { MockNetworkComponents } from '../mocks/index.js'
14
+ import type { Message, PubSub } from '@libp2p/interface/pubsub'
15
+
16
+ export default (common: TestSetup<PubSub, PubSubArgs>): void => {
17
+ describe('pubsub connection handlers', () => {
18
+ let psA: PubSub
19
+ let psB: PubSub
20
+ let componentsA: MockNetworkComponents
21
+ let componentsB: MockNetworkComponents
22
+
23
+ describe('nodes send state on connection', () => {
24
+ // Create pubsub nodes and connect them
25
+ beforeEach(async () => {
26
+ mockNetwork.reset()
27
+
28
+ componentsA = await createComponents()
29
+ componentsB = await createComponents()
30
+
31
+ psA = componentsA.pubsub = await common.setup({
32
+ components: componentsA,
33
+ init: {}
34
+ })
35
+
36
+ psB = componentsB.pubsub = await common.setup({
37
+ components: componentsB,
38
+ init: {}
39
+ })
40
+
41
+ // Start pubsub
42
+ await start(...Object.values(componentsA), ...Object.values(componentsB))
43
+
44
+ expect(psA.getPeers()).to.be.empty()
45
+ expect(psB.getPeers()).to.be.empty()
46
+
47
+ // Make subscriptions prior to nodes connected
48
+ psA.subscribe('Za')
49
+ psB.subscribe('Zb')
50
+
51
+ expect(psA.getPeers()).to.be.empty()
52
+ expect(psA.getTopics()).to.deep.equal(['Za'])
53
+ expect(psB.getPeers()).to.be.empty()
54
+ expect(psB.getTopics()).to.deep.equal(['Zb'])
55
+ })
56
+
57
+ afterEach(async () => {
58
+ sinon.restore()
59
+ await stop(...Object.values(componentsA), ...Object.values(componentsB))
60
+ await common.teardown()
61
+ mockNetwork.reset()
62
+ })
63
+
64
+ it('existing subscriptions are sent upon peer connection', async function () {
65
+ const subscriptionsChanged = Promise.all([
66
+ pEvent(psA, 'subscription-change'),
67
+ pEvent(psB, 'subscription-change')
68
+ ])
69
+
70
+ await componentsA.connectionManager.openConnection(componentsB.peerId)
71
+
72
+ await subscriptionsChanged
73
+
74
+ expect(psA.getPeers()).to.have.lengthOf(1)
75
+ expect(psB.getPeers()).to.have.lengthOf(1)
76
+
77
+ expect(psA.getTopics()).to.deep.equal(['Za'])
78
+ expect(psB.getTopics()).to.deep.equal(['Zb'])
79
+
80
+ expect(psA.getSubscribers('Zb').map(p => p.toString())).to.deep.equal([componentsB.peerId.toString()])
81
+ expect(psB.getSubscribers('Za').map(p => p.toString())).to.deep.equal([componentsA.peerId.toString()])
82
+ })
83
+ })
84
+
85
+ describe('pubsub started before connect', () => {
86
+ let psA: PubSub
87
+ let psB: PubSub
88
+ let componentsA: MockNetworkComponents
89
+ let componentsB: MockNetworkComponents
90
+
91
+ // Create pubsub nodes and start them
92
+ beforeEach(async () => {
93
+ mockNetwork.reset()
94
+ componentsA = await createComponents()
95
+ componentsB = await createComponents()
96
+
97
+ psA = componentsA.pubsub = await common.setup({
98
+ components: componentsA,
99
+ init: {}
100
+ })
101
+ psB = componentsB.pubsub = await common.setup({
102
+ components: componentsB,
103
+ init: {}
104
+ })
105
+
106
+ await start(...Object.values(componentsA), ...Object.values(componentsB))
107
+ })
108
+
109
+ afterEach(async () => {
110
+ sinon.restore()
111
+ await stop(...Object.values(componentsA), ...Object.values(componentsB))
112
+ await common.teardown()
113
+ mockNetwork.reset()
114
+ })
115
+
116
+ it('should get notified of connected peers on dial', async () => {
117
+ await componentsA.connectionManager.openConnection(componentsB.peerId)
118
+
119
+ return Promise.all([
120
+ pWaitFor(() => psA.getPeers().length === 1),
121
+ pWaitFor(() => psB.getPeers().length === 1)
122
+ ])
123
+ })
124
+
125
+ it('should receive pubsub messages', async () => {
126
+ const defer = pDefer()
127
+ const topic = 'test-topic'
128
+ const data = uint8ArrayFromString('hey!')
129
+
130
+ await componentsA.connectionManager.openConnection(componentsB.peerId)
131
+
132
+ let subscribedTopics = psA.getTopics()
133
+ expect(subscribedTopics).to.not.include(topic)
134
+
135
+ psA.subscribe(topic)
136
+ psA.addEventListener('message', (evt) => {
137
+ if (evt.detail.topic === topic) {
138
+ const msg = evt.detail
139
+ expect(msg.data).to.equalBytes(data)
140
+ defer.resolve()
141
+ }
142
+ })
143
+ psA.subscribe(topic)
144
+
145
+ subscribedTopics = psA.getTopics()
146
+ expect(subscribedTopics).to.include(topic)
147
+
148
+ // wait for psB to know about psA subscription
149
+ await pWaitFor(() => {
150
+ const subscribedPeers = psB.getSubscribers(topic)
151
+ return subscribedPeers.map(p => p.toString()).includes(componentsA.peerId.toString()) // eslint-disable-line max-nested-callbacks
152
+ })
153
+ await psB.publish(topic, data)
154
+
155
+ await defer.promise
156
+ })
157
+ })
158
+
159
+ describe('pubsub started after connect', () => {
160
+ let psA: PubSub
161
+ let psB: PubSub
162
+ let componentsA: MockNetworkComponents
163
+ let componentsB: MockNetworkComponents
164
+
165
+ // Create pubsub nodes
166
+ beforeEach(async () => {
167
+ mockNetwork.reset()
168
+ componentsA = await createComponents()
169
+ componentsB = await createComponents()
170
+
171
+ psA = componentsA.pubsub = await common.setup({
172
+ components: componentsA,
173
+ init: {}
174
+ })
175
+ psB = componentsB.pubsub = await common.setup({
176
+ components: componentsB,
177
+ init: {}
178
+ })
179
+ })
180
+
181
+ afterEach(async () => {
182
+ sinon.restore()
183
+ await stop(...Object.values(componentsA), ...Object.values(componentsB))
184
+ await common.teardown()
185
+ mockNetwork.reset()
186
+ })
187
+
188
+ it('should get notified of connected peers after starting', async () => {
189
+ await start(...Object.values(componentsA), ...Object.values(componentsB))
190
+
191
+ await componentsA.connectionManager.openConnection(componentsB.peerId)
192
+
193
+ return Promise.all([
194
+ pWaitFor(() => psA.getPeers().length === 1),
195
+ pWaitFor(() => psB.getPeers().length === 1)
196
+ ])
197
+ })
198
+
199
+ it('should receive pubsub messages', async () => {
200
+ const defer = pDefer()
201
+ const topic = 'test-topic'
202
+ const data = uint8ArrayFromString('hey!')
203
+
204
+ await start(...Object.values(componentsA), ...Object.values(componentsB))
205
+
206
+ await componentsA.connectionManager.openConnection(componentsB.peerId)
207
+
208
+ await Promise.all([
209
+ pWaitFor(() => psA.getPeers().length === 1),
210
+ pWaitFor(() => psB.getPeers().length === 1)
211
+ ])
212
+
213
+ let subscribedTopics = psA.getTopics()
214
+ expect(subscribedTopics).to.not.include(topic)
215
+
216
+ psA.subscribe(topic)
217
+ psA.addEventListener('message', (evt) => {
218
+ if (evt.detail.topic === topic) {
219
+ const msg = evt.detail
220
+ expect(msg.data).to.equalBytes(data)
221
+ defer.resolve()
222
+ }
223
+ })
224
+ psA.subscribe(topic)
225
+
226
+ subscribedTopics = psA.getTopics()
227
+ expect(subscribedTopics).to.include(topic)
228
+
229
+ // wait for psB to know about psA subscription
230
+ await pWaitFor(() => {
231
+ const subscribedPeers = psB.getSubscribers(topic)
232
+ return subscribedPeers.map(p => p.toString()).includes(componentsA.peerId.toString()) // eslint-disable-line max-nested-callbacks
233
+ })
234
+ await psB.publish(topic, data)
235
+
236
+ await defer.promise
237
+ })
238
+ })
239
+
240
+ describe('pubsub with intermittent connections', () => {
241
+ let psA: PubSub
242
+ let psB: PubSub
243
+ let componentsA: MockNetworkComponents
244
+ let componentsB: MockNetworkComponents
245
+
246
+ // Create pubsub nodes and start them
247
+ beforeEach(async () => {
248
+ mockNetwork.reset()
249
+ componentsA = await createComponents()
250
+ componentsB = await createComponents()
251
+
252
+ psA = componentsA.pubsub = await common.setup({
253
+ components: componentsA,
254
+ init: {}
255
+ })
256
+ psB = componentsB.pubsub = await common.setup({
257
+ components: componentsB,
258
+ init: {}
259
+ })
260
+
261
+ await start(...Object.values(componentsA), ...Object.values(componentsB))
262
+ })
263
+
264
+ afterEach(async () => {
265
+ sinon.restore()
266
+ await stop(...Object.values(componentsA), ...Object.values(componentsB))
267
+ await common.teardown()
268
+ mockNetwork.reset()
269
+ })
270
+
271
+ it.skip('should receive pubsub messages after a node restart', async function () {
272
+ const topic = 'test-topic'
273
+ const data = uint8ArrayFromString('hey!')
274
+
275
+ let counter = 0
276
+ const defer1 = pDefer()
277
+ const defer2 = pDefer()
278
+
279
+ await componentsA.connectionManager.openConnection(componentsB.peerId)
280
+
281
+ let subscribedTopics = psA.getTopics()
282
+ expect(subscribedTopics).to.not.include(topic)
283
+
284
+ psA.subscribe(topic)
285
+ psA.addEventListener('message', (evt) => {
286
+ if (evt.detail.topic === topic) {
287
+ const msg = evt.detail
288
+ expect(msg.data).to.equalBytes(data)
289
+ counter++
290
+ counter === 1 ? defer1.resolve() : defer2.resolve()
291
+ }
292
+ })
293
+ psA.subscribe(topic)
294
+
295
+ subscribedTopics = psA.getTopics()
296
+ expect(subscribedTopics).to.include(topic)
297
+
298
+ // wait for psB to know about psA subscription
299
+ await pWaitFor(() => {
300
+ const subscribedPeers = psB.getSubscribers(topic)
301
+ return subscribedPeers.map(p => p.toString()).includes(componentsA.peerId.toString()) // eslint-disable-line max-nested-callbacks
302
+ })
303
+ await psB.publish(topic, data)
304
+
305
+ await defer1.promise
306
+
307
+ await stop(psB)
308
+ await pWaitFor(() => {
309
+ // @ts-expect-error protected fields
310
+ const aHasConnectionToB = psA._libp2p.connectionManager.get(psB.peerId)
311
+ // @ts-expect-error protected fields
312
+ const bHasConnectionToA = psB._libp2p.connectionManager.get(psA.peerId)
313
+
314
+ return aHasConnectionToB != null && bHasConnectionToA != null
315
+ })
316
+ await start(psB)
317
+
318
+ await componentsA.connectionManager.openConnection(componentsB.peerId)
319
+
320
+ // wait for remoteLibp2p to know about libp2p subscription
321
+ await pWaitFor(() => {
322
+ const subscribedPeers = psB.getSubscribers(topic)
323
+ return subscribedPeers.toString().includes(componentsA.peerId.toString())
324
+ })
325
+
326
+ await psB.publish(topic, data)
327
+
328
+ await defer2.promise
329
+ })
330
+
331
+ it.skip('should handle quick reconnects with a delayed disconnect', async () => {
332
+ // Subscribe on both
333
+ let aReceivedFirstMessageFromB = false
334
+ let aReceivedSecondMessageFromB = false
335
+ let bReceivedFirstMessageFromA = false
336
+ let bReceivedSecondMessageFromA = false
337
+ const topic = 'reconnect-channel'
338
+
339
+ const handlerSpyA = (evt: CustomEvent<Message>): void => {
340
+ if (evt.detail.topic !== topic) {
341
+ return
342
+ }
343
+
344
+ const message = evt.detail
345
+ const data = uint8ArrayToString(message.data)
346
+
347
+ if (data === 'message-from-b-1') {
348
+ aReceivedFirstMessageFromB = true
349
+ }
350
+
351
+ if (data === 'message-from-b-2') {
352
+ aReceivedSecondMessageFromB = true
353
+ }
354
+ }
355
+ const handlerSpyB = (evt: CustomEvent<Message>): void => {
356
+ if (evt.detail.topic !== topic) {
357
+ return
358
+ }
359
+
360
+ const message = evt.detail
361
+ const data = uint8ArrayToString(message.data)
362
+
363
+ if (data === 'message-from-a-1') {
364
+ bReceivedFirstMessageFromA = true
365
+ }
366
+
367
+ if (data === 'message-from-a-2') {
368
+ bReceivedSecondMessageFromA = true
369
+ }
370
+ }
371
+
372
+ psA.addEventListener('message', handlerSpyA)
373
+ psB.addEventListener('message', handlerSpyB)
374
+ psA.subscribe(topic)
375
+ psB.subscribe(topic)
376
+
377
+ // Create two connections to the remote peer
378
+ // @ts-expect-error protected fields
379
+ const originalConnection = await psA._libp2p.dialer.connectToPeer(psB.peerId)
380
+
381
+ // second connection
382
+ await componentsA.connectionManager.openConnection(componentsB.peerId)
383
+
384
+ // Wait for subscriptions to occur
385
+ await pWaitFor(() => {
386
+ return psA.getSubscribers(topic).map(p => p.toString()).includes(componentsB.peerId.toString()) &&
387
+ psB.getSubscribers(topic).map(p => p.toString()).includes(componentsA.peerId.toString())
388
+ })
389
+
390
+ // Verify messages go both ways
391
+ await psA.publish(topic, uint8ArrayFromString('message-from-a-1'))
392
+ await psB.publish(topic, uint8ArrayFromString('message-from-b-1'))
393
+ await pWaitFor(() => {
394
+ return aReceivedFirstMessageFromB && bReceivedFirstMessageFromA
395
+ })
396
+
397
+ // Disconnect the first connection (this acts as a delayed reconnect)
398
+ // @ts-expect-error protected fields
399
+ const psAConnUpdateSpy = sinon.spy(psA._libp2p.connectionManager.connections, 'set')
400
+
401
+ await originalConnection.close()
402
+ await pWaitFor(() => psAConnUpdateSpy.callCount === 1)
403
+
404
+ // Verify messages go both ways after the disconnect
405
+ await psA.publish(topic, uint8ArrayFromString('message-from-a-2'))
406
+ await psB.publish(topic, uint8ArrayFromString('message-from-b-2'))
407
+ await pWaitFor(() => {
408
+ return aReceivedSecondMessageFromB && bReceivedSecondMessageFromA
409
+ })
410
+ })
411
+ })
412
+ })
413
+ }