@libp2p/interop 0.0.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 (75) hide show
  1. package/LICENSE +4 -0
  2. package/README.md +60 -0
  3. package/dist/src/connect.d.ts +3 -0
  4. package/dist/src/connect.d.ts.map +1 -0
  5. package/dist/src/connect.js +54 -0
  6. package/dist/src/connect.js.map +1 -0
  7. package/dist/src/dht/content-fetching.d.ts +3 -0
  8. package/dist/src/dht/content-fetching.d.ts.map +1 -0
  9. package/dist/src/dht/content-fetching.js +50 -0
  10. package/dist/src/dht/content-fetching.js.map +1 -0
  11. package/dist/src/dht/content-routing.d.ts +3 -0
  12. package/dist/src/dht/content-routing.d.ts.map +1 -0
  13. package/dist/src/dht/content-routing.js +50 -0
  14. package/dist/src/dht/content-routing.js.map +1 -0
  15. package/dist/src/dht/index.d.ts +3 -0
  16. package/dist/src/dht/index.d.ts.map +1 -0
  17. package/dist/src/dht/index.js +9 -0
  18. package/dist/src/dht/index.js.map +1 -0
  19. package/dist/src/dht/peer-routing.d.ts +3 -0
  20. package/dist/src/dht/peer-routing.d.ts.map +1 -0
  21. package/dist/src/dht/peer-routing.js +44 -0
  22. package/dist/src/dht/peer-routing.js.map +1 -0
  23. package/dist/src/index.d.ts +20 -0
  24. package/dist/src/index.d.ts.map +1 -0
  25. package/dist/src/index.js +9 -0
  26. package/dist/src/index.js.map +1 -0
  27. package/dist/src/pubsub/floodsub.d.ts +3 -0
  28. package/dist/src/pubsub/floodsub.d.ts.map +1 -0
  29. package/dist/src/pubsub/floodsub.js +52 -0
  30. package/dist/src/pubsub/floodsub.js.map +1 -0
  31. package/dist/src/pubsub/gossipsub.d.ts +3 -0
  32. package/dist/src/pubsub/gossipsub.d.ts.map +1 -0
  33. package/dist/src/pubsub/gossipsub.js +52 -0
  34. package/dist/src/pubsub/gossipsub.js.map +1 -0
  35. package/dist/src/pubsub/hybrid.d.ts +3 -0
  36. package/dist/src/pubsub/hybrid.d.ts.map +1 -0
  37. package/dist/src/pubsub/hybrid.js +52 -0
  38. package/dist/src/pubsub/hybrid.js.map +1 -0
  39. package/dist/src/pubsub/index.d.ts +3 -0
  40. package/dist/src/pubsub/index.d.ts.map +1 -0
  41. package/dist/src/pubsub/index.js +9 -0
  42. package/dist/src/pubsub/index.js.map +1 -0
  43. package/dist/src/resources/keys/go.ed25519.key +1 -0
  44. package/dist/src/resources/keys/go.rsa.key +0 -0
  45. package/dist/src/resources/keys/go.secp256k1.key +1 -0
  46. package/dist/src/resources/keys/index.d.ts +5 -0
  47. package/dist/src/resources/keys/index.d.ts.map +1 -0
  48. package/dist/src/resources/keys/index.js +18 -0
  49. package/dist/src/resources/keys/index.js.map +1 -0
  50. package/dist/src/resources/keys/js.ed25519.key +1 -0
  51. package/dist/src/resources/keys/js.rsa.key +0 -0
  52. package/dist/src/resources/keys/js.secp256k1.key +1 -0
  53. package/dist/src/utils/dht-record.d.ts +6 -0
  54. package/dist/src/utils/dht-record.d.ts.map +1 -0
  55. package/dist/src/utils/dht-record.js +10 -0
  56. package/dist/src/utils/dht-record.js.map +1 -0
  57. package/package.json +151 -0
  58. package/src/connect.ts +75 -0
  59. package/src/dht/content-fetching.ts +70 -0
  60. package/src/dht/content-routing.ts +74 -0
  61. package/src/dht/index.ts +10 -0
  62. package/src/dht/peer-routing.ts +63 -0
  63. package/src/index.ts +31 -0
  64. package/src/pubsub/floodsub.ts +70 -0
  65. package/src/pubsub/gossipsub.ts +70 -0
  66. package/src/pubsub/hybrid.ts +70 -0
  67. package/src/pubsub/index.ts +10 -0
  68. package/src/resources/keys/go.ed25519.key +1 -0
  69. package/src/resources/keys/go.rsa.key +0 -0
  70. package/src/resources/keys/go.secp256k1.key +1 -0
  71. package/src/resources/keys/index.ts +24 -0
  72. package/src/resources/keys/js.ed25519.key +1 -0
  73. package/src/resources/keys/js.rsa.key +0 -0
  74. package/src/resources/keys/js.secp256k1.key +1 -0
  75. package/src/utils/dht-record.ts +10 -0
@@ -0,0 +1 @@
1
+  {��ܥg� oT+.�\�L� Y��Jb���G�q7�
@@ -0,0 +1,5 @@
1
+ import type { NodeType, PeerIdType } from '../..';
2
+ declare type KeyCollection = Record<PeerIdType, string>;
3
+ export declare const keys: Record<NodeType, KeyCollection>;
4
+ export {};
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/resources/keys/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAIjD,aAAK,aAAa,GAAG,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;AAc/C,eAAO,MAAM,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,aAAa,CAGhD,CAAA"}
@@ -0,0 +1,18 @@
1
+ import path from 'path';
2
+ import { fileURLToPath } from 'url';
3
+ const __dirname = path.dirname(fileURLToPath(import.meta.url)); // eslint-disable-line @typescript-eslint/naming-convention
4
+ const goKeys = {
5
+ ed25519: path.join(__dirname, 'go.ed25519.key'),
6
+ rsa: path.join(__dirname, 'go.rsa.key'),
7
+ secp256k1: path.join(__dirname, 'go.secp256k1.key')
8
+ };
9
+ const jsKeys = {
10
+ ed25519: path.join(__dirname, 'js.ed25519.key'),
11
+ rsa: path.join(__dirname, 'js.rsa.key'),
12
+ secp256k1: path.join(__dirname, 'js.secp256k1.key')
13
+ };
14
+ export const keys = {
15
+ go: goKeys,
16
+ js: jsKeys
17
+ };
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/resources/keys/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAA;AAGnC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA,CAAC,2DAA2D;AAI1H,MAAM,MAAM,GAAkB;IAC5B,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC;IAC/C,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC;IACvC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC;CACpD,CAAA;AAED,MAAM,MAAM,GAAkB;IAC5B,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC;IAC/C,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC;IACvC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC;CACpD,CAAA;AAED,MAAM,CAAC,MAAM,IAAI,GAAoC;IACnD,EAAE,EAAE,MAAM;IACV,EAAE,EAAE,MAAM;CACX,CAAA"}
@@ -0,0 +1 @@
1
+ `F́o��.ux��7f�v71��{�z���9*x7Ӟ�g��Q�g,�FhŒ�0������]3�7Ӟ�g��Q�g,�FhŒ�0������]3�
@@ -0,0 +1 @@
1
+  �z�m�/�kPa�ࡓ$�Z���p"�>v��
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ key: Uint8Array;
3
+ value: Uint8Array;
4
+ };
5
+ export default _default;
6
+ //# sourceMappingURL=dht-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dht-record.d.ts","sourceRoot":"","sources":["../../../src/utils/dht-record.ts"],"names":[],"mappings":";;;;AAGA,wBAMC"}
@@ -0,0 +1,10 @@
1
+ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string';
2
+ import { concat as uint8ArrayConcat } from 'uint8arrays/concat';
3
+ export default {
4
+ key: uint8ArrayConcat([
5
+ uint8ArrayFromString('/pk/'),
6
+ uint8ArrayFromString('muft89xjpybos8eas1vaq2xrbsx2vkll7is4ocy7pia5fsjlt3c2', 'base36')
7
+ ]),
8
+ value: uint8ArrayFromString('080012a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100c2588f998971dac9e3eef76a311bf9159505aff69ea3b664c55a36aa28ee08de1127228a4d431bb9c0840240c75f6e98a0843a78d945491a3ea5e1f7cee2bc71383510db5290702383975b7bffae9fb40c84cc1220fb4a7db862fffb0de42f8fd8fb33a17deb20f30e2d0f194791fe69355a392f77df35f101e08a2fc95b2c018768938814fcb52482f899f5e90a1905e8abbcdbb1647ad80a5b0417e1ce8320d64197a6ba3848926375c63adebabdf6eb82109bcadfee13b62bf922bbb6f74c1a26c9bc6122d1436787e0e6de3c152b1959701092abef84599f73eaedb2fcef9f87293e1bbe8e0fef3f1a7fd2e8b94c7e633f88473644a63cb948e4d25c54490203010001', 'hex')
9
+ };
10
+ //# sourceMappingURL=dht-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dht-record.js","sourceRoot":"","sources":["../../../src/utils/dht-record.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAC5E,OAAO,EAAE,MAAM,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAE/D,eAAe;IACb,GAAG,EAAE,gBAAgB,CAAC;QACpB,oBAAoB,CAAC,MAAM,CAAC;QAC5B,oBAAoB,CAAC,sDAAsD,EAAE,QAAQ,CAAC;KACvF,CAAC;IACF,KAAK,EAAE,oBAAoB,CAAC,wlBAAwlB,EAAE,KAAK,CAAC;CAC7nB,CAAA"}
package/package.json ADDED
@@ -0,0 +1,151 @@
1
+ {
2
+ "name": "@libp2p/interop",
3
+ "version": "0.0.0",
4
+ "description": "Interoperability Tests for libp2p",
5
+ "license": "Apache-2.0 OR MIT",
6
+ "homepage": "https://github.com/libp2p/interop#readme",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/libp2p/interop.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/libp2p/interop/issues"
13
+ },
14
+ "keywords": [
15
+ "libp2p"
16
+ ],
17
+ "engines": {
18
+ "node": ">=16.0.0",
19
+ "npm": ">=7.0.0"
20
+ },
21
+ "type": "module",
22
+ "types": "./dist/src/index.d.ts",
23
+ "files": [
24
+ "src",
25
+ "dist/src",
26
+ "!dist/test",
27
+ "!**/*.tsbuildinfo"
28
+ ],
29
+ "exports": {
30
+ ".": {
31
+ "import": "./dist/src/index.js"
32
+ }
33
+ },
34
+ "eslintConfig": {
35
+ "extends": "ipfs",
36
+ "parserOptions": {
37
+ "sourceType": "module"
38
+ }
39
+ },
40
+ "release": {
41
+ "branches": [
42
+ "master"
43
+ ],
44
+ "plugins": [
45
+ [
46
+ "@semantic-release/commit-analyzer",
47
+ {
48
+ "preset": "conventionalcommits",
49
+ "releaseRules": [
50
+ {
51
+ "breaking": true,
52
+ "release": "major"
53
+ },
54
+ {
55
+ "revert": true,
56
+ "release": "patch"
57
+ },
58
+ {
59
+ "type": "feat",
60
+ "release": "minor"
61
+ },
62
+ {
63
+ "type": "fix",
64
+ "release": "patch"
65
+ },
66
+ {
67
+ "type": "chore",
68
+ "release": "patch"
69
+ },
70
+ {
71
+ "type": "docs",
72
+ "release": "patch"
73
+ },
74
+ {
75
+ "type": "test",
76
+ "release": "patch"
77
+ },
78
+ {
79
+ "scope": "no-release",
80
+ "release": false
81
+ }
82
+ ]
83
+ }
84
+ ],
85
+ [
86
+ "@semantic-release/release-notes-generator",
87
+ {
88
+ "preset": "conventionalcommits",
89
+ "presetConfig": {
90
+ "types": [
91
+ {
92
+ "type": "feat",
93
+ "section": "Features"
94
+ },
95
+ {
96
+ "type": "fix",
97
+ "section": "Bug Fixes"
98
+ },
99
+ {
100
+ "type": "chore",
101
+ "section": "Trivial Changes"
102
+ },
103
+ {
104
+ "type": "docs",
105
+ "section": "Trivial Changes"
106
+ },
107
+ {
108
+ "type": "test",
109
+ "section": "Tests"
110
+ }
111
+ ]
112
+ }
113
+ }
114
+ ],
115
+ "@semantic-release/changelog",
116
+ "@semantic-release/npm",
117
+ "@semantic-release/github",
118
+ "@semantic-release/git"
119
+ ]
120
+ },
121
+ "scripts": {
122
+ "lint": "aegir lint",
123
+ "dep-check": "aegir dep-check dist/src/**/*.js dist/test/**/*.js",
124
+ "build": "tsc",
125
+ "postbuild": "cp src/resources/keys/*.key dist/src/resources/keys",
126
+ "pretest": "npm run build",
127
+ "test": "aegir test -f \"./dist/test/**/*.spec.js\"",
128
+ "test:node": "npm run test -- -t node -f ./dist/test/node.js",
129
+ "test:chrome": "npm run test -- -t browser -f ./dist/test/browser.js ",
130
+ "test:firefox": "npm run test -- -t browser -- --browser firefox -f ./dist/test/browser.js",
131
+ "release": "semantic-release"
132
+ },
133
+ "dependencies": {
134
+ "@libp2p/daemon-client": "^0.0.2",
135
+ "@libp2p/interfaces": "^1.3.17",
136
+ "@libp2p/logger": "^1.1.2",
137
+ "@libp2p/peer-id": "^1.1.8",
138
+ "@multiformats/multiaddr": "^10.1.8",
139
+ "it-all": "^1.0.6",
140
+ "it-first": "^1.0.7",
141
+ "multiformats": "^9.4.5",
142
+ "p-retry": "^5.1.0",
143
+ "uint8arrays": "^3.0.0"
144
+ },
145
+ "peerDependencies": {
146
+ "aegir": "^36.0.0"
147
+ },
148
+ "devDependencies": {
149
+ "aegir": "^36.0.0"
150
+ }
151
+ }
package/src/connect.ts ADDED
@@ -0,0 +1,75 @@
1
+ import { expect } from 'aegir/utils/chai.js'
2
+ import type { Daemon, NodeType, SpawnOptions, DaemonFactory, PeerIdType } from './index.js'
3
+ import { keys } from './resources/keys/index.js'
4
+
5
+ export function connectTests (factory: DaemonFactory) {
6
+ const keyTypes: PeerIdType[] = ['ed25519', 'rsa', 'secp256k1']
7
+ const impls: NodeType[] = ['js', 'go']
8
+
9
+ for (const keyType of keyTypes) {
10
+ for (const implA of impls) {
11
+ for (const implB of impls) {
12
+ runConnectTests(
13
+ `noise/${keyType}`,
14
+ factory,
15
+ { type: implA, noise: true, key: keys.go[keyType] },
16
+ { type: implB, noise: true, key: keys.js[keyType] }
17
+ )
18
+ }
19
+ }
20
+ }
21
+ }
22
+
23
+ function runConnectTests (name: string, factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions) {
24
+ describe(`connect using ${name}`, () => {
25
+ let daemons: Daemon[]
26
+
27
+ // Start Daemons
28
+ before(async function () {
29
+ this.timeout(20 * 1000)
30
+
31
+ daemons = await Promise.all([
32
+ factory.spawn(optionsA),
33
+ factory.spawn(optionsB)
34
+ ])
35
+ })
36
+
37
+ // Stop daemons
38
+ after(async function () {
39
+ if (daemons != null) {
40
+ await Promise.all(
41
+ daemons.map(async (daemon) => await daemon.stop())
42
+ )
43
+ }
44
+ })
45
+
46
+ it(`${optionsA.type} peer to ${optionsB.type} peer`, async function () {
47
+ this.timeout(10 * 1000)
48
+
49
+ const identify1 = await daemons[0].client.identify()
50
+ const identify2 = await daemons[1].client.identify()
51
+
52
+ // verify connected peers
53
+ const knownPeersBeforeConnect1 = await daemons[0].client.listPeers()
54
+ expect(knownPeersBeforeConnect1).to.have.lengthOf(0)
55
+
56
+ const knownPeersBeforeConnect2 = await daemons[1].client.listPeers()
57
+ expect(knownPeersBeforeConnect2).to.have.lengthOf(0)
58
+
59
+ // connect peers
60
+ await daemons[0].client.connect(identify2.peerId, identify2.addrs)
61
+
62
+ // daemons[0] will take some time to get the peers
63
+ await new Promise(resolve => setTimeout(resolve, 1000))
64
+
65
+ // verify connected peers
66
+ const knownPeersAfterConnect1 = await daemons[0].client.listPeers()
67
+ expect(knownPeersAfterConnect1).to.have.lengthOf(1)
68
+ expect(knownPeersAfterConnect1[0].toString()).to.equal(identify2.peerId.toString())
69
+
70
+ const knownPeersAfterConnect2 = await daemons[1].client.listPeers()
71
+ expect(knownPeersAfterConnect2).to.have.lengthOf(1)
72
+ expect(knownPeersAfterConnect2[0].toString()).to.equal(identify1.peerId.toString())
73
+ })
74
+ })
75
+ }
@@ -0,0 +1,70 @@
1
+ /* eslint-env mocha */
2
+
3
+ import { expect } from 'aegir/utils/chai.js'
4
+ import type { Daemon, DaemonFactory, NodeType, SpawnOptions } from '../index.js'
5
+ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
6
+ import { concat as uint8ArrayConcat } from 'uint8arrays/concat'
7
+
8
+ const record = {
9
+ key: uint8ArrayConcat([
10
+ uint8ArrayFromString('/pk/'),
11
+ uint8ArrayFromString('muft89xjpybos8eas1vaq2xrbsx2vkll7is4ocy7pia5fsjlt3c2', 'base36')
12
+ ]),
13
+ value: uint8ArrayFromString('080012a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100c2588f998971dac9e3eef76a311bf9159505aff69ea3b664c55a36aa28ee08de1127228a4d431bb9c0840240c75f6e98a0843a78d945491a3ea5e1f7cee2bc71383510db5290702383975b7bffae9fb40c84cc1220fb4a7db862fffb0de42f8fd8fb33a17deb20f30e2d0f194791fe69355a392f77df35f101e08a2fc95b2c018768938814fcb52482f899f5e90a1905e8abbcdbb1647ad80a5b0417e1ce8320d64197a6ba3848926375c63adebabdf6eb82109bcadfee13b62bf922bbb6f74c1a26c9bc6122d1436787e0e6de3c152b1959701092abef84599f73eaedb2fcef9f87293e1bbe8e0fef3f1a7fd2e8b94c7e633f88473644a63cb948e4d25c54490203010001', 'hex')
14
+ }
15
+
16
+ export function contentFetchingTests (factory: DaemonFactory) {
17
+ const nodeTypes: NodeType[] = ['js', 'go']
18
+
19
+ for (const typeA of nodeTypes) {
20
+ for (const typeB of nodeTypes) {
21
+ runContentFetchingTests(
22
+ factory,
23
+ { type: typeA, dht: true },
24
+ { type: typeB, dht: true }
25
+ )
26
+ }
27
+ }
28
+ }
29
+
30
+ function runContentFetchingTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions) {
31
+ describe('dht.contentFetching', () => {
32
+ let daemons: Daemon[]
33
+
34
+ // Start Daemons
35
+ before(async function () {
36
+ this.timeout(20 * 1000)
37
+
38
+ daemons = await Promise.all([
39
+ factory.spawn(optionsA),
40
+ factory.spawn(optionsB)
41
+ ])
42
+
43
+ // connect them
44
+ const identify0 = await daemons[0].client.identify()
45
+
46
+ await daemons[1].client.connect(identify0.peerId, identify0.addrs)
47
+
48
+ // jsDaemon1 will take some time to get the peers
49
+ await new Promise(resolve => setTimeout(resolve, 1000))
50
+ })
51
+
52
+ // Stop daemons
53
+ after(async function () {
54
+ if (daemons != null) {
55
+ await Promise.all(
56
+ daemons.map(async (daemon) => await daemon.stop())
57
+ )
58
+ }
59
+ })
60
+
61
+ it(`${optionsA.type} peer to ${optionsB.type} peer`, async function () {
62
+ this.timeout(10 * 1000)
63
+
64
+ await daemons[0].client.dht.put(record.key, record.value)
65
+
66
+ const data = await daemons[1].client.dht.get(record.key)
67
+ expect(data).to.equalBytes(record.value)
68
+ })
69
+ })
70
+ }
@@ -0,0 +1,74 @@
1
+ /* eslint-env mocha */
2
+
3
+ import { expect } from 'aegir/utils/chai.js'
4
+ import { CID } from 'multiformats/cid'
5
+ import all from 'it-all'
6
+ import type { Daemon, DaemonFactory, NodeType, SpawnOptions } from '../index.js'
7
+ import type { IdentifyResult } from '@libp2p/daemon-client'
8
+
9
+ export function contentRoutingTests (factory: DaemonFactory) {
10
+ const nodeTypes: NodeType[] = ['js', 'go']
11
+
12
+ for (const typeA of nodeTypes) {
13
+ for (const typeB of nodeTypes) {
14
+ if (typeA === 'go' && typeB === 'go') {
15
+ // skip go<->go as it never seems to populate the routing tables
16
+ continue
17
+ }
18
+
19
+ runContentRoutingTests(
20
+ factory,
21
+ { type: typeA, dht: true },
22
+ { type: typeB, dht: true }
23
+ )
24
+ }
25
+ }
26
+ }
27
+
28
+ function runContentRoutingTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions) {
29
+ describe('dht.contentRouting', () => {
30
+ let daemons: Daemon[]
31
+ let identify: IdentifyResult[]
32
+
33
+ // Start Daemons
34
+ before(async function () {
35
+ this.timeout(20 * 1000)
36
+
37
+ daemons = await Promise.all([
38
+ factory.spawn(optionsA),
39
+ factory.spawn(optionsB),
40
+ factory.spawn(optionsB)
41
+ ])
42
+
43
+ identify = await Promise.all(
44
+ daemons.map(async d => await d.client.identify())
45
+ )
46
+
47
+ await daemons[0].client.connect(identify[1].peerId, identify[1].addrs)
48
+ await daemons[0].client.connect(identify[2].peerId, identify[2].addrs)
49
+
50
+ // get the peers in the table
51
+ await new Promise(resolve => setTimeout(resolve, 1000))
52
+ })
53
+
54
+ // Stop daemons
55
+ after(async function () {
56
+ if (daemons != null) {
57
+ await Promise.all(
58
+ daemons.map(async (daemon) => await daemon.stop())
59
+ )
60
+ }
61
+ })
62
+
63
+ it(`${optionsA.type} peer to ${optionsB.type} peer`, async function () {
64
+ const cid = CID.parse('QmVzw6MPsF96TyXBSRs1ptLoVMWRv5FCYJZZGJSVB2Hp39')
65
+
66
+ await daemons[0].client.dht.provide(cid)
67
+
68
+ const providers = await all(daemons[1].client.dht.findProviders(cid, 1))
69
+
70
+ expect(providers).to.exist()
71
+ expect(providers.length).to.be.greaterThan(0)
72
+ })
73
+ })
74
+ }
@@ -0,0 +1,10 @@
1
+ import type { DaemonFactory } from '../index.js'
2
+ import { contentFetchingTests } from './content-fetching.js'
3
+ import { contentRoutingTests } from './content-routing.js'
4
+ import { peerRoutingTests } from './peer-routing.js'
5
+
6
+ export async function dhtTests (factory: DaemonFactory) {
7
+ await contentFetchingTests(factory)
8
+ await contentRoutingTests(factory)
9
+ await peerRoutingTests(factory)
10
+ }
@@ -0,0 +1,63 @@
1
+ /* eslint-env mocha */
2
+
3
+ import { expect } from 'aegir/utils/chai.js'
4
+ import type { Daemon, DaemonFactory, NodeType, SpawnOptions } from '../index.js'
5
+ import pRetry from 'p-retry'
6
+ import type { PeerInfo } from '@libp2p/interfaces/peer-info'
7
+
8
+ export function peerRoutingTests (factory: DaemonFactory) {
9
+ const nodeTypes: NodeType[] = ['js', 'go']
10
+
11
+ for (const typeA of nodeTypes) {
12
+ for (const typeB of nodeTypes) {
13
+ runPeerRoutingTests(
14
+ factory,
15
+ { type: typeA, dht: true },
16
+ { type: typeB, dht: true }
17
+ )
18
+ }
19
+ }
20
+ }
21
+
22
+ function runPeerRoutingTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions) {
23
+ describe('dht.peerRouting', () => {
24
+ let daemons: Daemon[]
25
+
26
+ // Start Daemons
27
+ before(async function () {
28
+ this.timeout(20 * 1000)
29
+
30
+ daemons = await Promise.all([
31
+ factory.spawn(optionsA),
32
+ factory.spawn(optionsB),
33
+ factory.spawn(optionsB)
34
+ ])
35
+ })
36
+
37
+ // Stop daemons
38
+ after(async function () {
39
+ if (daemons != null) {
40
+ await Promise.all(
41
+ daemons.map(async (daemon) => await daemon.stop())
42
+ )
43
+ }
44
+ })
45
+
46
+ it(`${optionsA.type} peer to ${optionsB.type} peer`, async function () {
47
+ const identify1 = await daemons[1].client.identify()
48
+ const identify2 = await daemons[2].client.identify()
49
+
50
+ // peers need at least one peer in their routing table or they fail with:
51
+ // connect 0 => 1
52
+ await daemons[0].client.connect(identify1.peerId, identify1.addrs)
53
+
54
+ // connect 0 => 2
55
+ await daemons[0].client.connect(identify2.peerId, identify2.addrs)
56
+
57
+ // peer 1 find peer 2, retry up to 10 times to allow the routing table to refresh
58
+ const peerData: PeerInfo = await pRetry(async () => await daemons[1].client.dht.findPeer(identify2.peerId), { retries: 10 })
59
+
60
+ expect(identify2.addrs.map(ma => ma.toString())).to.include.deep.members(peerData.multiaddrs.map(ma => ma.toString()))
61
+ })
62
+ })
63
+ }
package/src/index.ts ADDED
@@ -0,0 +1,31 @@
1
+ import { connectTests } from './connect.js'
2
+ import { dhtTests } from './dht/index.js'
3
+ import { pubsubTests } from './pubsub/index.js'
4
+ import type { DaemonClient } from '@libp2p/daemon-client'
5
+
6
+ export interface Daemon {
7
+ stop: () => Promise<void>
8
+ client: DaemonClient
9
+ }
10
+
11
+ export type NodeType = 'js' | 'go'
12
+ export type PeerIdType = 'rsa' | 'ed25519' | 'secp256k1'
13
+
14
+ export interface SpawnOptions {
15
+ type: NodeType
16
+ key?: string
17
+ noise?: true
18
+ dht?: boolean
19
+ pubsub?: boolean
20
+ pubsubRouter?: 'gossipsub' | 'floodsub'
21
+ }
22
+
23
+ export interface DaemonFactory {
24
+ spawn: (options: SpawnOptions) => Promise<Daemon>
25
+ }
26
+
27
+ export default async function interopTests (factory: DaemonFactory) {
28
+ await connectTests(factory)
29
+ await dhtTests(factory)
30
+ await pubsubTests(factory)
31
+ }
@@ -0,0 +1,70 @@
1
+ /* eslint-env mocha */
2
+
3
+ import { expect } from 'aegir/utils/chai.js'
4
+ import type { Daemon, DaemonFactory, NodeType, SpawnOptions } from '../index.js'
5
+ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
6
+ import first from 'it-first'
7
+
8
+ export function floodsubTests (factory: DaemonFactory) {
9
+ const nodeTypes: NodeType[] = ['js', 'go']
10
+
11
+ for (const typeA of nodeTypes) {
12
+ for (const typeB of nodeTypes) {
13
+ runFloodsubTests(
14
+ factory,
15
+ { type: typeA, pubsub: true, pubsubRouter: 'floodsub' },
16
+ { type: typeB, pubsub: true, pubsubRouter: 'floodsub' }
17
+ )
18
+ }
19
+ }
20
+ }
21
+
22
+ function runFloodsubTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions) {
23
+ describe('pubsub.floodSub', () => {
24
+ let daemons: Daemon[]
25
+
26
+ // Start Daemons
27
+ before(async function () {
28
+ this.timeout(20 * 1000)
29
+
30
+ daemons = await Promise.all([
31
+ factory.spawn(optionsA),
32
+ factory.spawn(optionsB),
33
+ factory.spawn(optionsB)
34
+ ])
35
+ })
36
+
37
+ // Stop daemons
38
+ after(async function () {
39
+ if (daemons != null) {
40
+ await Promise.all(
41
+ daemons.map(async (daemon) => await daemon.stop())
42
+ )
43
+ }
44
+ })
45
+
46
+ it(`${optionsA.type} peer to ${optionsB.type} peer`, async function () {
47
+ const topic = 'test-topic'
48
+ const data = uint8ArrayFromString('test-data')
49
+
50
+ const subscribeIterator = await daemons[1].client.pubsub.subscribe(topic)
51
+ const subscriber = async () => {
52
+ const message = await first(subscribeIterator)
53
+
54
+ expect(message).to.exist()
55
+ expect(message).to.have.property('data').that.equalBytes(data)
56
+ }
57
+
58
+ const publisher = async () => {
59
+ // wait for subscription stream
60
+ await new Promise(resolve => setTimeout(resolve, 800))
61
+ await daemons[0].client.pubsub.publish(topic, data)
62
+ }
63
+
64
+ return await Promise.all([
65
+ subscriber(),
66
+ publisher()
67
+ ])
68
+ })
69
+ })
70
+ }