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,576 @@
1
+ /*
2
+ Unit tests for the pubsub/messaging.js library.
3
+ */
4
+
5
+ // npm libraries
6
+ import { assert } from 'chai'
7
+ import sinon from 'sinon'
8
+ import SlpWallet from 'minimal-slp-wallet'
9
+ import cloneDeep from 'lodash.clonedeep'
10
+
11
+ // local libraries
12
+ import Messaging from '../../../../lib/adapters/pubsub-adapter/messaging.js'
13
+ import ipfsLib from '../../../mocks/ipfs-mock.js'
14
+ import IPFSAdapter from '../../../../lib/adapters/ipfs-adapter.js'
15
+ import EncryptionAdapter from '../../../../lib/adapters/encryption-adapter.js'
16
+ import BchAdapter from '../../../../lib/adapters/bch-adapter.js'
17
+ import thisNode from '../../../mocks/thisnode-mocks.js'
18
+ import ResendMsg from '../../../../lib/adapters/pubsub-adapter/resend-msg.js'
19
+
20
+ describe('#messaging-adapter', () => {
21
+ let sandbox
22
+ let uut
23
+ let ipfs, ipfsAdapter
24
+
25
+ const log = {
26
+ statusLog: () => {}
27
+ }
28
+
29
+ beforeEach(async () => {
30
+ // Restore the sandbox before each test.
31
+ sandbox = sinon.createSandbox()
32
+
33
+ // Instantiate the IPFS adapter
34
+ ipfs = cloneDeep(ipfsLib)
35
+ ipfsAdapter = new IPFSAdapter({ ipfs, log })
36
+
37
+ // Instantiate the Encryption adapater
38
+ const wallet = new SlpWallet()
39
+ await wallet.walletInfoPromise
40
+ const bch = new BchAdapter({ wallet })
41
+ const encryption = new EncryptionAdapter({ bch })
42
+
43
+ // Instantiate the library under test. Must instantiate dependencies first.
44
+ uut = new Messaging({ ipfsAdapter, log, encryption })
45
+ })
46
+
47
+ afterEach(() => sandbox.restore())
48
+
49
+ describe('#constructor', () => {
50
+ it('should throw an error if IPFS adapter not specified', () => {
51
+ try {
52
+ uut = new Messaging()
53
+
54
+ assert.fail('Unexpected result')
55
+ } catch (err) {
56
+ assert.include(
57
+ err.message,
58
+ 'Instance of IPFS adapter required when instantiating Messaging Adapter.'
59
+ )
60
+ }
61
+ })
62
+
63
+ it('should throw an error if log adapter not specified', () => {
64
+ try {
65
+ uut = new Messaging({ ipfsAdapter })
66
+
67
+ assert.fail('Unexpected result')
68
+ } catch (err) {
69
+ assert.include(
70
+ err.message,
71
+ 'A status log handler function required when instantitating Messaging Adapter'
72
+ )
73
+ }
74
+ })
75
+
76
+ it('should throw an error if log adapter not specified', () => {
77
+ try {
78
+ uut = new Messaging({ ipfsAdapter, log })
79
+
80
+ assert.fail('Unexpected result')
81
+ } catch (err) {
82
+ assert.include(
83
+ err.message,
84
+ 'An instance of the encryption Adapter must be passed when instantiating the Messaging Adapter library.'
85
+ )
86
+ }
87
+ })
88
+ })
89
+
90
+ describe('#generateMsgObj', () => {
91
+ it('should throw error if sender is not specified', () => {
92
+ try {
93
+ uut.generateMsgObj()
94
+
95
+ assert.fail('Unexpected code path')
96
+ } catch (err) {
97
+ assert.equal(err.message, 'Sender required when calling generateMsgObj()')
98
+ }
99
+ })
100
+
101
+ it('should throw error if Receiver is not specified', () => {
102
+ try {
103
+ const inObj = {
104
+ sender: 'fake-sender'
105
+ }
106
+
107
+ uut.generateMsgObj(inObj)
108
+
109
+ assert.fail('Unexpected code path')
110
+ } catch (err) {
111
+ assert.equal(err.message, 'Receiver required when calling generateMsgObj()')
112
+ }
113
+ })
114
+
115
+ it('should throw error if payload is not specified', () => {
116
+ try {
117
+ const inObj = {
118
+ sender: 'fake-sender',
119
+ receiver: 'fake-receiver'
120
+ }
121
+
122
+ uut.generateMsgObj(inObj)
123
+
124
+ assert.fail('Unexpected code path')
125
+ } catch (err) {
126
+ assert.equal(err.message, 'Payload required when calling generateMsgObj()')
127
+ }
128
+ })
129
+
130
+ it('should generate a message object', () => {
131
+ const inObj = {
132
+ sender: 'fake-sender',
133
+ receiver: 'fake-receiver',
134
+ payload: 'fake-payload'
135
+ }
136
+
137
+ const result = uut.generateMsgObj(inObj)
138
+ // console.log(result)
139
+
140
+ assert.property(result, 'timestamp')
141
+ assert.property(result, 'uuid')
142
+ assert.property(result, 'sender')
143
+ assert.property(result, 'receiver')
144
+ assert.property(result, 'payload')
145
+ })
146
+ })
147
+
148
+ describe('#generateAckMsg', () => {
149
+ it('should generate an ACK message', async () => {
150
+ const ipfsId = '12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa'
151
+ const data = {
152
+ sender: ipfsId,
153
+ uuid: 'fake-uuid'
154
+ }
155
+
156
+ thisNode.peerData.push({ from: ipfsId })
157
+
158
+ const result = await uut.generateAckMsg(data, thisNode)
159
+ // console.log(result)
160
+
161
+ assert.property(result, 'timestamp')
162
+ assert.property(result, 'uuid')
163
+ assert.property(result, 'sender')
164
+ assert.property(result, 'receiver')
165
+ assert.property(result, 'payload')
166
+ })
167
+ })
168
+
169
+ it('should catch and throw errors', async () => {
170
+ try {
171
+ await uut.generateAckMsg()
172
+
173
+ assert.fail('Unexpected code path')
174
+ } catch (err) {
175
+ console.log(err)
176
+ assert.include(err.message, 'Cannot read')
177
+ }
178
+ })
179
+
180
+ describe('#publishToPubsubChannel', () => {
181
+ it('should publish a message to a pubsub channel', async () => {
182
+ const chanName = 'fake-chanName'
183
+
184
+ const inObj = {
185
+ sender: 'fake-sender',
186
+ receiver: 'fake-receiver',
187
+ payload: 'fake-payload'
188
+ }
189
+ const msgObj = uut.generateMsgObj(inObj)
190
+
191
+ const result = await uut.publishToPubsubChannel(chanName, msgObj)
192
+
193
+ // assert.equal(true, true, 'Not throwing an error is a pass')
194
+ assert.equal(result, true)
195
+ })
196
+
197
+ it('should announce itself on the announcement pubsub channel', async () => {
198
+ const chanName = 'fake-chanName'
199
+
200
+ const inObj = {
201
+ sender: 'fake-sender',
202
+ receiver: 'fake-receiver',
203
+ payload: 'fake-payload'
204
+ }
205
+ const msgObj = uut.generateMsgObj(inObj)
206
+ delete msgObj.uuid
207
+
208
+ const result = await uut.publishToPubsubChannel(chanName, msgObj)
209
+
210
+ // assert.equal(true, true, 'Not throwing an error is a pass')
211
+ assert.equal(result, true)
212
+ })
213
+
214
+ it('should catch and throw errors', async () => {
215
+ try {
216
+ // Force an error
217
+ sandbox
218
+ .stub(uut.ipfs.ipfs.pubsub, 'publish')
219
+ .rejects(new Error('test error'))
220
+
221
+ await uut.publishToPubsubChannel()
222
+
223
+ assert.fail('Unexpected code path')
224
+ } catch (err) {
225
+ // console.log('err: ', err)
226
+ assert.include(err.message, 'The first argument')
227
+ }
228
+ })
229
+ })
230
+
231
+ describe('#_checkIfAlreadyProcessed', () => {
232
+ it('should return true if UUID is already in cache', () => {
233
+ const uuid = 'fake-uuid'
234
+
235
+ // Force uuid to be in cache
236
+ uut.msgCache.push(uuid)
237
+
238
+ const result = uut._checkIfAlreadyProcessed(uuid)
239
+
240
+ assert.equal(result, true)
241
+ })
242
+
243
+ it('should return false and add uuid to cache', () => {
244
+ const uuid = 'fake-uuid'
245
+
246
+ const result = uut._checkIfAlreadyProcessed(uuid)
247
+
248
+ assert.equal(result, false)
249
+
250
+ assert.equal(uut.msgCache.includes(uuid), true)
251
+ })
252
+
253
+ it('should shift out the oldest element if the cache is full', () => {
254
+ const uuid = 'fake-uuid'
255
+
256
+ // Force code path for this test.
257
+ uut.MSG_CACHE_SIZE = 0
258
+
259
+ const result = uut._checkIfAlreadyProcessed(uuid)
260
+
261
+ assert.equal(result, false)
262
+ })
263
+ })
264
+
265
+ describe('#resendMsg', () => {
266
+ it('should resend message', async () => {
267
+ // Mock dependencies
268
+ sandbox.stub(uut, 'publishToPubsubChannel').resolves()
269
+
270
+ const inObj = {
271
+ sender: 'fake-sender',
272
+ receiver: 'fake-receiver',
273
+ payload: 'fake-payload'
274
+ }
275
+ const msgObj = uut.generateMsgObj(inObj)
276
+ msgObj.retryCnt = 0
277
+
278
+ const resendMsg = new ResendMsg({ msgObj, msgLib: uut })
279
+
280
+ const result = await resendMsg.resend()
281
+
282
+ assert.equal(result, 1)
283
+ })
284
+
285
+ it('should clear the Interval if retry count has been exceeded', async () => {
286
+ const inObj = {
287
+ sender: 'fake-sender',
288
+ receiver: 'fake-receiver',
289
+ payload: 'fake-payload'
290
+ }
291
+ const msgObj = uut.generateMsgObj(inObj)
292
+ msgObj.retryCnt = 4
293
+
294
+ const resendMsg = new ResendMsg({ msgObj, msgLib: uut })
295
+
296
+ const result = await resendMsg.resend()
297
+
298
+ assert.equal(result, 2)
299
+ })
300
+
301
+ it('should return 0 on error', async () => {
302
+ // const result = await uut.resendMsg()
303
+ const resendMsg = new ResendMsg({ msgObj: {}, msgLib: {} })
304
+
305
+ const result = await resendMsg.resend()
306
+
307
+ assert.equal(result, 0)
308
+ })
309
+ })
310
+
311
+ describe('#addMsgToQueue', () => {
312
+ it('should add a message to the queue', () => {
313
+ const inObj = {
314
+ sender: 'fake-sender',
315
+ receiver: 'fake-receiver',
316
+ payload: 'fake-payload'
317
+ }
318
+ const msgObj = uut.generateMsgObj(inObj)
319
+
320
+ const result = uut.addMsgToQueue(msgObj)
321
+ // console.log(result)
322
+
323
+ clearInterval(result.intervalHandle)
324
+
325
+ assert.property(result, 'timestamp')
326
+ assert.property(result, 'uuid')
327
+ assert.property(result, 'sender')
328
+ assert.property(result, 'receiver')
329
+ assert.property(result, 'payload')
330
+ assert.property(result, 'intervalHandle')
331
+ assert.property(result, 'retryCnt')
332
+ })
333
+
334
+ it('should catch and throw errors', async () => {
335
+ try {
336
+ // Force an error
337
+ sandbox.stub(uut.msgQueue, 'push').throws(new Error('test error'))
338
+
339
+ await uut.addMsgToQueue()
340
+
341
+ assert.fail('Unexpected code path')
342
+ } catch (err) {
343
+ // console.log('err: ', err)
344
+ assert.include(err.message, 'test error')
345
+ }
346
+ })
347
+ })
348
+
349
+ describe('#delMsgFromQueue', () => {
350
+ it('should delete a message from the queue', () => {
351
+ const inObj = {
352
+ sender: 'fake-sender',
353
+ receiver: 'fake-receiver',
354
+ payload: 'fake-payload'
355
+ }
356
+ const msgObj = uut.generateMsgObj(inObj)
357
+
358
+ // Force the object to be in the queue
359
+ uut.msgQueue.push(msgObj)
360
+
361
+ const result = uut.delMsgFromQueue(msgObj)
362
+
363
+ assert.equal(result, true)
364
+ })
365
+ })
366
+
367
+ describe('#sendMsg', () => {
368
+ it('should send a message to an IPFS peer', async () => {
369
+ // Mock dependencies
370
+ sandbox.stub(uut, 'generateMsgObj').returns({ key: 'value' })
371
+ sandbox.stub(uut, 'publishToPubsubChannel').resolves()
372
+ sandbox.stub(uut, 'addMsgToQueue').returns()
373
+
374
+ const receiver = 'fake-receiver'
375
+ const payload = 'fake-payload'
376
+
377
+ const result = await uut.sendMsg(receiver, payload, thisNode)
378
+
379
+ assert.equal(result, true)
380
+ })
381
+
382
+ it('should catch and throw errors', async () => {
383
+ try {
384
+ // Force an error
385
+ sandbox.stub(uut, 'generateMsgObj').throws(new Error('test error'))
386
+
387
+ const receiver = 'fake-receiver'
388
+ const payload = 'fake-payload'
389
+
390
+ await uut.sendMsg(receiver, payload, thisNode)
391
+
392
+ assert.fail('Unexpected code path')
393
+ } catch (err) {
394
+ // console.log('err: ', err)
395
+ assert.include(err.message, 'test error')
396
+ }
397
+ })
398
+ })
399
+
400
+ describe('#sendAck', () => {
401
+ it('should send an ACK message', async () => {
402
+ // Mock dependencies
403
+ sandbox.stub(uut, 'publishToPubsubChannel').resolves()
404
+
405
+ const ipfsId = '12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa'
406
+ const data = {
407
+ sender: ipfsId,
408
+ uuid: 'fake-uuid'
409
+ }
410
+
411
+ const result = await uut.sendAck(data, thisNode)
412
+
413
+ assert.equal(result, true)
414
+ })
415
+
416
+ it('should catch and throw errors', async () => {
417
+ try {
418
+ // Force an error
419
+ sandbox.stub(uut, 'generateAckMsg').throws(new Error('test error'))
420
+
421
+ const ipfsId = '12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa'
422
+ const data = {
423
+ sender: ipfsId,
424
+ uuid: 'fake-uuid'
425
+ }
426
+
427
+ await uut.sendAck(data, thisNode)
428
+
429
+ assert.fail('Unexpected code path')
430
+ } catch (err) {
431
+ // console.log('err: ', err)
432
+ assert.include(err.message, 'test error')
433
+ }
434
+ })
435
+ })
436
+
437
+ describe('#handleIncomingData', () => {
438
+ it('should handle an incoming message', async () => {
439
+ // Mock dependencies
440
+ // sandbox.stub(uut.encryption,'decryptMsg').resolves()
441
+ uut.encryption.decryptMsg = (x) => JSON.stringify(x)
442
+ sandbox.stub(uut, 'sendAck').resolves()
443
+ sandbox.stub(uut, '_checkIfAlreadyProcessed').returns(false)
444
+
445
+ uut.nodeType = 'external'
446
+
447
+ const msg = {
448
+ from: '12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa',
449
+ topicIDs: ['12D3KooWE6tkdArVpCHG9QN61G1cE7eCq2Q7i4bNx6CJFTDprk9f'],
450
+ data: new TextEncoder().encode('{"payload": {"key": "value"}}')
451
+ }
452
+
453
+ const result = await uut.handleIncomingData(msg, thisNode)
454
+ // console.log(result)
455
+
456
+ assert.property(result, 'from')
457
+ assert.property(result, 'channel')
458
+ assert.property(result, 'data')
459
+ })
460
+
461
+ it('should return false for incoming ACK message', async () => {
462
+ // Mock dependencies
463
+ // sandbox.stub(uut.encryption,'decryptMsg').resolves()
464
+ uut.encryption.decryptMsg = (x) => JSON.stringify(x)
465
+ sandbox.stub(uut, 'sendAck').resolves()
466
+ sandbox.stub(uut, '_checkIfAlreadyProcessed').returns(false)
467
+ sandbox.stub(uut, 'delMsgFromQueue').returns()
468
+
469
+ uut.nodeType = 'external'
470
+
471
+ const msg = {
472
+ from: '12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa',
473
+ topicIDs: ['12D3KooWE6tkdArVpCHG9QN61G1cE7eCq2Q7i4bNx6CJFTDprk9f'],
474
+ data: new TextEncoder().encode('{"payload": {"apiName": "ACK"}}')
475
+ }
476
+
477
+ const result = await uut.handleIncomingData(msg, thisNode)
478
+ // console.log(result)
479
+
480
+ assert.equal(result, false)
481
+ })
482
+
483
+ it('should return false for already processed message', async () => {
484
+ // Mock dependencies
485
+ // sandbox.stub(uut.encryption,'decryptMsg').resolves()
486
+ uut.encryption.decryptMsg = (x) => JSON.stringify(x)
487
+ sandbox.stub(uut, 'sendAck').resolves()
488
+ sandbox.stub(uut, '_checkIfAlreadyProcessed').returns(true)
489
+ sandbox.stub(uut, 'delMsgFromQueue').returns()
490
+
491
+ uut.nodeType = 'external'
492
+
493
+ const msg = {
494
+ from: '12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa',
495
+ topicIDs: ['12D3KooWE6tkdArVpCHG9QN61G1cE7eCq2Q7i4bNx6CJFTDprk9f'],
496
+ data: new TextEncoder().encode('{"payload": {"key": "value"}}')
497
+ }
498
+
499
+ const result = await uut.handleIncomingData(msg, thisNode)
500
+ // console.log(result)
501
+
502
+ assert.equal(result, false)
503
+ })
504
+
505
+ it('should return false on error', async () => {
506
+ const result = await uut.handleIncomingData()
507
+
508
+ assert.equal(result, false)
509
+ })
510
+
511
+ it('should return false if message originates from this node', async () => {
512
+ // Mock dependencies
513
+ uut.encryption.decryptMsg = (x) => JSON.stringify(x)
514
+ sandbox.stub(uut, 'sendAck').resolves()
515
+ sandbox.stub(uut, '_checkIfAlreadyProcessed').returns(false)
516
+
517
+ uut.nodeType = 'external'
518
+
519
+ const msg = {
520
+ from: '12D3KooWE6tkdArVpCHG9QN61G1cE7eCq2Q7i4bNx6CJFTDprk9f',
521
+ topicIDs: ['12D3KooWE6tkdArVpCHG9QN61G1cE7eCq2Q7i4bNx6CJFTDprk9f'],
522
+ data: new TextEncoder().encode('{"payload": {"key": "value"}}')
523
+ }
524
+
525
+ const result = await uut.handleIncomingData(msg, thisNode)
526
+ // console.log(result)
527
+
528
+ assert.equal(result, false)
529
+ })
530
+
531
+ it('should report debug REQUESTS from an about RPC call', async () => {
532
+ // Force desired code path
533
+ uut.encryption.decryptMsg = (x) => JSON.stringify({
534
+ id: 123
535
+ })
536
+ sandbox.stub(uut, 'sendAck').resolves()
537
+ sandbox.stub(uut, '_checkIfAlreadyProcessed').returns(false)
538
+
539
+ uut.nodeType = 'external'
540
+
541
+ const msg = {
542
+ from: '12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa',
543
+ topicIDs: ['12D3KooWE6tkdArVpCHG9QN61G1cE7eCq2Q7i4bNx6CJFTDprk9f'],
544
+ data: new TextEncoder().encode('{"payload": {"key": "value"}}')
545
+ }
546
+
547
+ const result = await uut.handleIncomingData(msg, thisNode)
548
+ // console.log(result)
549
+
550
+ assert.include(result.data.payload, '123')
551
+ })
552
+
553
+ it('should report debug RESPONSE from an about RPC call', async () => {
554
+ // Force desired code path
555
+ uut.encryption.decryptMsg = (x) => JSON.stringify({
556
+ id: 123,
557
+ result: true
558
+ })
559
+ sandbox.stub(uut, 'sendAck').resolves()
560
+ sandbox.stub(uut, '_checkIfAlreadyProcessed').returns(false)
561
+
562
+ uut.nodeType = 'external'
563
+
564
+ const msg = {
565
+ from: '12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa',
566
+ topicIDs: ['12D3KooWE6tkdArVpCHG9QN61G1cE7eCq2Q7i4bNx6CJFTDprk9f'],
567
+ data: new TextEncoder().encode('{"payload": {"key": "value"}}')
568
+ }
569
+
570
+ const result = await uut.handleIncomingData(msg, thisNode)
571
+ // console.log(result)
572
+
573
+ assert.include(result.data.payload, '123')
574
+ })
575
+ })
576
+ })