helia-coord 1.1.0

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 (57) hide show
  1. package/.on-save.json +8 -0
  2. package/PEDIGREE.md +3 -0
  3. package/README.md +3 -0
  4. package/config/bootstrap-circuit-relays.js +48 -0
  5. package/examples/start-external.js +56 -0
  6. package/index.js +129 -0
  7. package/lib/adapters/bch-adapter.js +94 -0
  8. package/lib/adapters/encryption-adapter.js +123 -0
  9. package/lib/adapters/gist.js +42 -0
  10. package/lib/adapters/index.js +66 -0
  11. package/lib/adapters/ipfs-adapter.js +263 -0
  12. package/lib/adapters/logs-adapter.js +44 -0
  13. package/lib/adapters/pubsub-adapter/README.md +86 -0
  14. package/lib/adapters/pubsub-adapter/about-adapter.js +117 -0
  15. package/lib/adapters/pubsub-adapter/index.js +275 -0
  16. package/lib/adapters/pubsub-adapter/messaging.js +389 -0
  17. package/lib/adapters/pubsub-adapter/msg-router.js +58 -0
  18. package/lib/adapters/pubsub-adapter/resend-msg.js +58 -0
  19. package/lib/controllers/index.js +24 -0
  20. package/lib/controllers/timer-controller.js +417 -0
  21. package/lib/entities/this-node-entity.js +102 -0
  22. package/lib/use-cases/index.js +36 -0
  23. package/lib/use-cases/peer-use-cases.js +146 -0
  24. package/lib/use-cases/pubsub-use-cases.js +56 -0
  25. package/lib/use-cases/relay-use-cases.js +479 -0
  26. package/lib/use-cases/schema.js +158 -0
  27. package/lib/use-cases/this-node-use-cases.js +443 -0
  28. package/lib/util/utils.js +12 -0
  29. package/package.json +52 -0
  30. package/test/mocks/adapter-mock.js +119 -0
  31. package/test/mocks/circuit-relay-mocks.js +67 -0
  32. package/test/mocks/ipfs-mock.js +46 -0
  33. package/test/mocks/peers-mock.js +75 -0
  34. package/test/mocks/pubsub-mocks.js +37 -0
  35. package/test/mocks/thisnode-mocks.js +82 -0
  36. package/test/mocks/use-case-mocks.js +24 -0
  37. package/test/unit/adapters/bch-adapter-unit.js +96 -0
  38. package/test/unit/adapters/encryption-adapter-unit.js +129 -0
  39. package/test/unit/adapters/gist.unit.adapters.js +58 -0
  40. package/test/unit/adapters/index-adapters-unit.js +79 -0
  41. package/test/unit/adapters/ipfs-adapter-unit.js +215 -0
  42. package/test/unit/adapters/logs-adapter-unit.js +55 -0
  43. package/test/unit/adapters/pubsub/about-adapter-unit.js +129 -0
  44. package/test/unit/adapters/pubsub/messaging-adapter-unit.js +576 -0
  45. package/test/unit/adapters/pubsub/pubsub-adapter-unit.js +367 -0
  46. package/test/unit/adapters/pubsub/resend-msg-adapter-unit.js +58 -0
  47. package/test/unit/controllers/controllers-index-unit.js +30 -0
  48. package/test/unit/controllers/timer-controller-unit.js +261 -0
  49. package/test/unit/entities/this-node.unit.entity.js +157 -0
  50. package/test/unit/index-unit.js +160 -0
  51. package/test/unit/use-cases/peer.unit.use-cases.js +186 -0
  52. package/test/unit/use-cases/pubsub.unit.use-cases.js +114 -0
  53. package/test/unit/use-cases/relay-use-cases-unit.js +658 -0
  54. package/test/unit/use-cases/schema-use-case-unit.js +101 -0
  55. package/test/unit/use-cases/this-node-use-cases-unit.js +427 -0
  56. package/test/unit/use-cases/use-cases-index-unit.js +47 -0
  57. package/test/unit/util/utils-unit.js +31 -0
@@ -0,0 +1,261 @@
1
+ /*
2
+ Unit tests for the main Controllers index.js file.
3
+ */
4
+
5
+ // npm libraries
6
+ import { assert } from 'chai'
7
+ import sinon from 'sinon'
8
+
9
+ // Local libraries
10
+ import TimerControllers from '../../../lib/controllers/timer-controller.js'
11
+ import AdapterMock from '../../mocks/adapter-mock.js'
12
+ import UseCasesMock from '../../mocks/use-case-mocks.js'
13
+ import ThisNodeUseCases from '../../../lib/use-cases/this-node-use-cases.js'
14
+
15
+ const adapters = new AdapterMock()
16
+
17
+ describe('#Controllers-Timer', () => {
18
+ let uut
19
+ let sandbox
20
+ let useCases
21
+ let thisNode
22
+ let clock
23
+
24
+ beforeEach(async () => {
25
+ // Restore the sandbox before each test.
26
+ sandbox = sinon.createSandbox()
27
+ clock = sinon.useFakeTimers()
28
+
29
+ uut = new TimerControllers({
30
+ adapters,
31
+ statusLog: () => {
32
+ }
33
+ })
34
+
35
+ const thisNodeUseCases = new ThisNodeUseCases({
36
+ adapters,
37
+ controllers: {},
38
+ statusLog: () => {
39
+ }
40
+ })
41
+ thisNode = await thisNodeUseCases.createSelf({ type: 'node.js' })
42
+
43
+ useCases = new UseCasesMock()
44
+ })
45
+
46
+ afterEach(() => {
47
+ sandbox.restore()
48
+ clock.restore()
49
+
50
+ uut.stopAllTimers()
51
+ })
52
+
53
+ after(() => {
54
+ console.log('Stopping all timers')
55
+ uut.stopAllTimers()
56
+ })
57
+
58
+ describe('#constructor', () => {
59
+ it('should throw an error if adapters is not included', () => {
60
+ try {
61
+ uut = new TimerControllers()
62
+ } catch (err) {
63
+ assert.include(
64
+ err.message,
65
+ 'Instance of adapters required when instantiating Timer Controllers'
66
+ )
67
+ }
68
+ })
69
+
70
+ it('should throw an error if status log handler is not included', () => {
71
+ try {
72
+ uut = new TimerControllers({ adapters })
73
+ } catch (err) {
74
+ assert.include(
75
+ err.message,
76
+ 'Handler for status logs required when instantiating Timer Controllers'
77
+ )
78
+ }
79
+ })
80
+ })
81
+
82
+ describe('#startTimers', () => {
83
+ it('should start the timers', () => {
84
+ const result = uut.startTimers()
85
+
86
+ assert.property(result, 'circuitRelayTimerHandle')
87
+ assert.property(result, 'announceTimerHandle')
88
+ assert.property(result, 'peerTimerHandle')
89
+ assert.property(result, 'relaySearchHandle')
90
+ assert.property(result, 'checkBlacklistHandle')
91
+ assert.property(result, 'listPubsubChannelsHandle')
92
+
93
+ // Clean up test by stopping the timers.
94
+ clearInterval(result.circuitRelayTimerHandle)
95
+ clearInterval(result.announceTimerHandle)
96
+ clearInterval(result.peerTimerHandle)
97
+ clearInterval(result.relaySearchHandle)
98
+ clearInterval(result.checkBlacklistHandle)
99
+ clearInterval(result.listPubsubChannelsHandle)
100
+ })
101
+
102
+ it('should execute the functions inside the timers', () => {
103
+ // Mock all functions inside the timers so they don't actually execute.
104
+ sandbox.stub(uut, 'manageCircuitRelays').resolves()
105
+ sandbox.stub(uut, 'manageAnnouncement').resolves()
106
+ sandbox.stub(uut, 'managePeers').resolves()
107
+ sandbox.stub(uut, 'searchForRelays').resolves()
108
+ sandbox.stub(uut, 'listPubsubChannels').resolves()
109
+
110
+ uut.startTimers()
111
+ clock.tick(200000)
112
+
113
+ assert.isOk(true)
114
+ })
115
+ })
116
+
117
+ describe('#manageCircuitRelays', () => {
118
+ it('should refresh connections with known circuit relays', async () => {
119
+ const result = await uut.manageCircuitRelays(thisNode, useCases)
120
+
121
+ // Force the timer interval to excute.
122
+ clock.tick(200000)
123
+
124
+ assert.equal(result, true)
125
+ })
126
+
127
+ it('should catch and report an error', async () => {
128
+ // Force an error
129
+ sandbox
130
+ .stub(useCases.relays, 'connectToCRs')
131
+ .rejects(new Error('test error'))
132
+
133
+ const result = await uut.manageCircuitRelays(thisNode, useCases)
134
+
135
+ // Force the timer interval to excute.
136
+ clock.tick(200000)
137
+
138
+ assert.equal(result, false)
139
+ })
140
+ })
141
+
142
+ describe('#manageAnnouncement', () => {
143
+ it('should publish an announcement to the general coordination pubsub channel', async () => {
144
+ const result = await uut.manageAnnouncement(thisNode, useCases)
145
+
146
+ // Force the timer interval to excute.
147
+ clock.tick(200000)
148
+
149
+ assert.equal(result, true)
150
+ })
151
+
152
+ it('should catch and report an error', async () => {
153
+ // Force an error
154
+ sandbox
155
+ .stub(thisNode.schema, 'announcement')
156
+ .throws(new Error('test error'))
157
+
158
+ const result = await uut.manageAnnouncement(thisNode, useCases)
159
+
160
+ // Force the timer interval to excute.
161
+ clock.tick(200000)
162
+
163
+ assert.equal(result, false)
164
+ })
165
+ })
166
+
167
+ describe('#managePeers', () => {
168
+ it('should refresh connections to peers', async () => {
169
+ const result = await uut.managePeers(thisNode, useCases)
170
+
171
+ // Force the timer interval to excute.
172
+ clock.tick(200000)
173
+
174
+ assert.equal(result, true)
175
+ })
176
+
177
+ it('should catch and report an error', async () => {
178
+ // Force an error
179
+ sandbox
180
+ .stub(useCases.thisNode, 'refreshPeerConnections')
181
+ .throws(new Error('test error'))
182
+
183
+ const result = await uut.managePeers(thisNode, useCases)
184
+
185
+ // Force the timer interval to excute.
186
+ clock.tick(200000)
187
+
188
+ assert.equal(result, false)
189
+ })
190
+ })
191
+
192
+ describe('#blacklist', () => {
193
+ it('should return true after executing the use case', async () => {
194
+ const result = await uut.blacklist(thisNode, useCases)
195
+
196
+ // Force the timer interval to excute.
197
+ clock.tick(200000)
198
+
199
+ assert.equal(result, true)
200
+ })
201
+
202
+ it('should return false on error', async () => {
203
+ // Force an error
204
+ // sandbox
205
+ // .stub(useCases.thisNode, 'enforceBlacklist')
206
+ // .rejects(new Error('test error'))
207
+ sandbox
208
+ .stub(useCases.thisNode, 'enforceWhitelist')
209
+ .rejects(new Error('test error'))
210
+
211
+ const result = await uut.blacklist(thisNode, useCases)
212
+
213
+ // Force the timer interval to excute.
214
+ clock.tick(200000)
215
+
216
+ assert.equal(result, false)
217
+ })
218
+ })
219
+
220
+ describe('#searchForRelays', () => {
221
+ it('should find and relay-potential peers that are not in the relayData array', async () => {
222
+ // Mock test data
223
+ const thisNode = {
224
+ relayData: [{ ipfsId: 'id1' }],
225
+ peerData: [{ from: 'id2', data: { isCircuitRelay: true } }]
226
+ }
227
+
228
+ const result = await uut.searchForRelays(thisNode, useCases)
229
+
230
+ // Force the timer interval to excute.
231
+ clock.tick(200000)
232
+
233
+ assert.equal(result, true)
234
+ })
235
+
236
+ it('should report errors but not throw them', async () => {
237
+ const result = await uut.searchForRelays()
238
+
239
+ // Force the timer interval to excute.
240
+ clock.tick(200000)
241
+
242
+ assert.equal(result, false)
243
+ })
244
+ })
245
+
246
+ describe('#listPubsubChannels', () => {
247
+ it('should list pubsub channels', async () => {
248
+ const result = await uut.listPubsubChannels()
249
+
250
+ assert.equal(result, true)
251
+ })
252
+ })
253
+
254
+ // describe('#monitorBandwidth', () => {
255
+ // it('should report bandwidth', async () => {
256
+ // const result = await uut.monitorBandwidth(thisNode, useCases)
257
+
258
+ // assert.equal(result, true)
259
+ // })
260
+ // })
261
+ })
@@ -0,0 +1,157 @@
1
+ /*
2
+ Unit tests for the thisNode Entity
3
+ */
4
+
5
+ // npm libraries
6
+ import { assert } from 'chai'
7
+ import sinon from 'sinon'
8
+
9
+ // local libraries
10
+ import ThisNodeEntity from '../../../lib/entities/this-node-entity.js'
11
+
12
+ describe('#thisNode-Entity', () => {
13
+ let sandbox
14
+ let uut // Unit Under Test
15
+
16
+ beforeEach(() => {
17
+ // Restore the sandbox before each test.
18
+ sandbox = sinon.createSandbox()
19
+
20
+ // const bchjs = new BCHJS()
21
+ // uut = new IpfsCoord({ bchjs, ipfs, type: 'node.js' })
22
+ })
23
+
24
+ afterEach(() => sandbox.restore())
25
+
26
+ describe('#constructor', () => {
27
+ it('should throw an error if ipfsId is not included', () => {
28
+ try {
29
+ const configObj = {}
30
+
31
+ uut = new ThisNodeEntity(configObj)
32
+
33
+ assert.fail('Unexpected code path')
34
+ } catch (err) {
35
+ assert.include(
36
+ err.message,
37
+ 'ipfsId required when instantiating thisNode Entity'
38
+ )
39
+ }
40
+ })
41
+
42
+ it('should throw an error if multiaddrs are not included', () => {
43
+ try {
44
+ const configObj = {
45
+ ipfsId: 'fake-ipfsId'
46
+ }
47
+
48
+ uut = new ThisNodeEntity(configObj)
49
+
50
+ assert.fail('Unexpected code path')
51
+ } catch (err) {
52
+ assert.include(
53
+ err.message,
54
+ 'ipfsMultiaddrs required when instantiating thisNode Entity'
55
+ )
56
+ }
57
+ })
58
+
59
+ it('should throw an error if bchAddr is not included', () => {
60
+ try {
61
+ const configObj = {
62
+ ipfsId: 'fake-ipfsId',
63
+ ipfsMultiaddrs: ['fake-addr']
64
+ }
65
+
66
+ uut = new ThisNodeEntity(configObj)
67
+
68
+ assert.fail('Unexpected code path')
69
+ } catch (err) {
70
+ assert.include(
71
+ err.message,
72
+ 'bchAddr required when instantiating thisNode Entity'
73
+ )
74
+ }
75
+ })
76
+
77
+ it('should throw an error if slpAddr is not included', () => {
78
+ try {
79
+ const configObj = {
80
+ ipfsId: 'fake-ipfsId',
81
+ ipfsMultiaddrs: ['fake-addr'],
82
+ bchAddr: 'fake-addr'
83
+ }
84
+
85
+ uut = new ThisNodeEntity(configObj)
86
+
87
+ assert.fail('Unexpected code path')
88
+ } catch (err) {
89
+ assert.include(
90
+ err.message,
91
+ 'slpAddr required when instantiating thisNode Entity'
92
+ )
93
+ }
94
+ })
95
+
96
+ it('should throw an error if publicKey is not included', () => {
97
+ try {
98
+ const configObj = {
99
+ ipfsId: 'fake-ipfsId',
100
+ ipfsMultiaddrs: ['fake-addr'],
101
+ bchAddr: 'fake-addr',
102
+ slpAddr: 'fake-addr'
103
+ }
104
+
105
+ uut = new ThisNodeEntity(configObj)
106
+
107
+ assert.fail('Unexpected code path')
108
+ } catch (err) {
109
+ assert.include(
110
+ err.message,
111
+ 'publicKey required when instantiating thisNode Entity'
112
+ )
113
+ }
114
+ })
115
+
116
+ it('should throw an error if node type is not included', () => {
117
+ try {
118
+ const configObj = {
119
+ ipfsId: 'fake-ipfsId',
120
+ ipfsMultiaddrs: ['fake-addr'],
121
+ bchAddr: 'fake-addr',
122
+ slpAddr: 'fake-addr',
123
+ publicKey: 'fake-key'
124
+ }
125
+
126
+ uut = new ThisNodeEntity(configObj)
127
+
128
+ assert.fail('Unexpected code path')
129
+ } catch (err) {
130
+ assert.include(
131
+ err.message,
132
+ "Node type of 'node.js' or 'browser' required when instantiating thisNode Entity"
133
+ )
134
+ }
135
+ })
136
+
137
+ it('should create a thisNode Entity', () => {
138
+ const configObj = {
139
+ ipfsId: 'fake-ipfsId',
140
+ ipfsMultiaddrs: ['fake-addr'],
141
+ bchAddr: 'fake-addr',
142
+ slpAddr: 'fake-addr',
143
+ publicKey: 'fake-key',
144
+ type: 'node.js'
145
+ }
146
+
147
+ uut = new ThisNodeEntity(configObj)
148
+
149
+ assert.property(uut, 'ipfsId')
150
+ assert.property(uut, 'ipfsMultiaddrs')
151
+ assert.property(uut, 'bchAddr')
152
+ assert.property(uut, 'slpAddr')
153
+ assert.property(uut, 'publicKey')
154
+ assert.property(uut, 'type')
155
+ })
156
+ })
157
+ })
@@ -0,0 +1,160 @@
1
+ /*
2
+ Unit tests for the main index.js file.
3
+ */
4
+
5
+ // Global npm libraries
6
+ import { assert } from 'chai'
7
+ import sinon from 'sinon'
8
+ import SlpWallet from 'minimal-slp-wallet'
9
+
10
+ // Local libraries
11
+ import IpfsCoord from '../../index.js'
12
+ import ipfs from '../mocks/ipfs-mock.js'
13
+
14
+ describe('#ipfs-coord - index.js', () => {
15
+ let sandbox
16
+ let uut // Unit Under Test
17
+ let wallet
18
+
19
+ beforeEach(async () => {
20
+ // Restore the sandbox before each test.
21
+ sandbox = sinon.createSandbox()
22
+
23
+ wallet = new SlpWallet()
24
+ await wallet.walletInfoPromise
25
+
26
+ uut = new IpfsCoord({ wallet, ipfs, type: 'node.js' })
27
+ })
28
+
29
+ afterEach(() => sandbox.restore())
30
+
31
+ describe('#constructor', () => {
32
+ it('should throw an error if ipfs instance is not passed as input', () => {
33
+ try {
34
+ uut = new IpfsCoord({})
35
+
36
+ assert.fail('Unexpected code path')
37
+ } catch (err) {
38
+ assert.include(
39
+ err.message,
40
+ 'An instance of IPFS must be passed when instantiating the ipfs-coord library.'
41
+ )
42
+ }
43
+ })
44
+
45
+ it('should throw an error if bch-js instance is not passed as input', () => {
46
+ try {
47
+ uut = new IpfsCoord({ ipfs })
48
+
49
+ assert.fail('Unexpected code path')
50
+ } catch (err) {
51
+ assert.include(
52
+ err.message,
53
+ 'An instance of minimal-slp-wallet must be passed when instantiating the ipfs-coord library.'
54
+ )
55
+ }
56
+ })
57
+
58
+ it('should throw an error if node type is not defined', () => {
59
+ try {
60
+ const wallet = new SlpWallet()
61
+ uut = new IpfsCoord({ ipfs, wallet })
62
+
63
+ assert.fail('Unexpected code path')
64
+ } catch (err) {
65
+ assert.include(
66
+ err.message,
67
+ 'The type of IPFS node (browser or node.js) must be specified.'
68
+ )
69
+ }
70
+ })
71
+
72
+ it('should override default logs', async () => {
73
+ uut = new IpfsCoord({
74
+ wallet,
75
+ ipfs,
76
+ type: 'node.js',
77
+ statusLog: console.log,
78
+ privateLog: console.log
79
+ })
80
+ })
81
+
82
+ it('should set debugLevel to 0 if not specified', () => {
83
+ uut = new IpfsCoord({
84
+ wallet,
85
+ ipfs,
86
+ type: 'node.js',
87
+ statusLog: console.log,
88
+ privateLog: console.log
89
+ })
90
+
91
+ assert.equal(uut.debugLevel, 0)
92
+ })
93
+
94
+ it('should set debugLevel to 2 if specified', () => {
95
+ uut = new IpfsCoord({
96
+ wallet,
97
+ ipfs,
98
+ type: 'node.js',
99
+ statusLog: console.log,
100
+ privateLog: console.log,
101
+ debugLevel: 2
102
+ })
103
+
104
+ assert.equal(uut.debugLevel, 2)
105
+ })
106
+
107
+ it('should default debugLevel to 0 non-integer is used', () => {
108
+ uut = new IpfsCoord({
109
+ wallet,
110
+ ipfs,
111
+ type: 'node.js',
112
+ statusLog: console.log,
113
+ privateLog: console.log,
114
+ debugLevel: 'abcd'
115
+ })
116
+
117
+ assert.equal(uut.debugLevel, 0)
118
+ })
119
+ })
120
+
121
+ describe('#start', () => {
122
+ it('should return true after ipfs-coord dependencies have been started.', async () => {
123
+ // Mock the dependencies.
124
+ sandbox.stub(uut.adapters.ipfs, 'start').resolves({})
125
+ sandbox.stub(uut.useCases.thisNode, 'createSelf').resolves({})
126
+ sandbox.stub(uut.useCases.relays, 'initializeRelays').resolves({})
127
+ sandbox.stub(uut.useCases.pubsub, 'initializePubsub').resolves({})
128
+ sandbox.stub(uut.controllers.timer, 'startTimers').resolves({})
129
+ sandbox.stub(uut, '_initializeConnections').resolves({})
130
+
131
+ const result = await uut.start()
132
+
133
+ assert.equal(result, true)
134
+ })
135
+ })
136
+
137
+ describe('#_initializeConnections', () => {
138
+ it('should kick-off initial connections', async () => {
139
+ // Mock dependencies
140
+ sandbox.stub(uut.useCases.relays, 'initializeRelays').resolves()
141
+ sandbox.stub(uut.useCases.relays, 'getCRGist').resolves()
142
+ sandbox.stub(uut.useCases.thisNode, 'refreshPeerConnections').resolves()
143
+
144
+ const result = await uut._initializeConnections()
145
+
146
+ assert.equal(result, true)
147
+ })
148
+
149
+ it('should return falses on error', async () => {
150
+ // Force and error
151
+ sandbox
152
+ .stub(uut.useCases.relays, 'initializeRelays')
153
+ .rejects(new Error('test error'))
154
+
155
+ const result = await uut._initializeConnections()
156
+
157
+ assert.equal(result, false)
158
+ })
159
+ })
160
+ })