Skip to content
This repository was archived by the owner on Aug 1, 2023. It is now read-only.

Commit 7063e6f

Browse files
lidelachingbrain
andauthoredDec 16, 2021
feat: pubsub multibase and expanded dht (#410)
Updates `pubsub` interop tests with HTTP RPC wire format changes introduced in ipfs/js-ipfs#3922 and ipfs/kubo#8183 and runs against the code from mentioned PRs (js-ipfs from ipfs/js-ipfs#3922 + go-ipfs 0.11.0-rc1) to ensure things work end-to-end. Expands DHT tests. Co-authored-by: achingbrain <alex@achingbrain.net>
1 parent 1ffe4d0 commit 7063e6f

12 files changed

+3226
-3571
lines changed
 

‎.github/workflows/test.yml

+7-7
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ on:
77
# To run CI against unrelased go-ipfs or js-ipfs-* code (eg. wip PR),
88
# uncomment env below and define git revisions in ./scripts/custom-runtime.sh
99

10-
env:
11-
IPFS_GO_EXEC: /tmp/go-ipfs/cmd/ipfs/ipfs
10+
#env:
11+
#IPFS_GO_EXEC: /tmp/go-ipfs/cmd/ipfs/ipfs
1212
#IPFS_JS_EXEC: /tmp/js-ipfs/packages/ipfs/src/cli.js
1313
#IPFS_JS_MODULE: /tmp/js-ipfs/packages/ipfs/dist/cjs/src/index.js
1414
#IPFS_JS_HTTP_MODULE: /tmp/js-ipfs/packages/ipfs-http-client/dist/cjs/src/index.js
@@ -31,7 +31,7 @@ jobs:
3131
with:
3232
path: |
3333
/tmp/*-ipfs/**
34-
./go-libp2p-relay-daemon
34+
./scripts/libp2p-relay-daemon
3535
~/.npm
3636
./node_modules
3737
key: ${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ github.event.pull_request.head.sha }}
@@ -57,7 +57,7 @@ jobs:
5757
with:
5858
path: |
5959
/tmp/*-ipfs/**
60-
./go-libp2p-relay-daemon
60+
./scripts/libp2p-relay-daemon
6161
~/.npm
6262
./node_modules
6363
key: ${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ github.event.pull_request.head.sha }}
@@ -86,7 +86,7 @@ jobs:
8686
with:
8787
path: |
8888
/tmp/*-ipfs/**
89-
./go-libp2p-relay-daemon
89+
./scripts/libp2p-relay-daemon
9090
~/.npm
9191
./node_modules
9292
key: ${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ github.event.pull_request.head.sha }}
@@ -122,7 +122,7 @@ jobs:
122122
with:
123123
path: |
124124
/tmp/*-ipfs/**
125-
./go-libp2p-relay-daemon
125+
./scripts/libp2p-relay-daemon
126126
~/.npm
127127
./node_modules
128128
key: ${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ github.event.pull_request.head.sha }}
@@ -155,7 +155,7 @@ jobs:
155155
with:
156156
path: |
157157
/tmp/*-ipfs/**
158-
./go-libp2p-relay-daemon
158+
./scripts/libp2p-relay-daemon
159159
~/.npm
160160
./node_modules
161161
key: ${{ runner.os }}-build-${{ env.CACHE_NAME }}-${{ github.event.pull_request.head.sha }}

‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,5 @@ test/test-data/go-ipfs-repo/LOG
3939
test/test-data/go-ipfs-repo/LOG.old
4040
types
4141
go-libp2p-relay-daemon
42+
scripts/libp2p-relay-daemon
4243
*.identity

‎package-lock.json

+2,707-3,488
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+17-8
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"npm": ">6.0.0"
2424
},
2525
"scripts": {
26-
"postinstall": "./scripts/setup-relayd.sh",
26+
"postinstall": "cross-env node ./scripts/setup-libp2p-relay-daemon.js",
2727
"clean": "rimraf /tmp/js-ipfs /tmp/go-ipfs ./go-libp2p-relay-daemon",
2828
"lint": "aegir lint",
2929
"build": "aegir build",
@@ -52,35 +52,45 @@
5252
"execa": false
5353
},
5454
"dependencies": {
55-
"aegir": "^35.0.2",
55+
"aegir": "^36.0.2",
5656
"assert": "^2.0.0",
5757
"buffer": "^6.0.3",
58+
"cachedir": "^2.3.0",
5859
"cross-env": "^7.0.2",
5960
"delay": "^5.0.0",
6061
"detect-node": "^2.0.4",
62+
"execa": "^5.1.1",
63+
"go-platform": "^1.0.0",
64+
"got": "^12.0.0",
65+
"gunzip-maybe": "^1.4.2",
66+
"hasha": "^5.2.2",
6167
"ipfs-unixfs": "^6.0.3",
6268
"ipfs-utils": "^9.0.1",
6369
"ipfsd-ctl": "^10.0.3",
64-
"ipns": "^0.15.0",
70+
"ipns": "^0.16.0",
6571
"is-ci": "^3.0.0",
6672
"is-os": "^1.0.1",
6773
"iso-random-stream": "^2.0.0",
6874
"it-all": "^1.0.1",
6975
"it-concat": "^2.0.0",
7076
"it-drain": "^1.0.0",
7177
"it-last": "^1.0.1",
78+
"it-to-buffer": "^2.0.1",
7279
"libp2p-webrtc-star-signalling-server": "^0.1.0",
7380
"libp2p-websockets": "^0.16.1",
7481
"multiformats": "^9.3.0",
7582
"nanoid": "^3.1.10",
83+
"p-defer": "^3.0.0",
7684
"p-retry": "^4.1.0",
77-
"peer-id": "^0.15.1",
85+
"peer-id": "^0.16.0",
7886
"pretty-bytes": "^5.1.0",
7987
"promisify-es6": "^1.0.3",
8088
"random-fs": "^1.0.3",
8189
"readable-stream-buffer-stream": "^1.0.0",
8290
"rimraf": "^3.0.2",
91+
"tar-fs": "^2.1.1",
8392
"uint8arrays": "^3.0.0",
93+
"unzip-stream": "^0.3.1",
8494
"wherearewe": "^1.0.0"
8595
},
8696
"contributors": [
@@ -101,9 +111,8 @@
101111
"Richard Littauer <richard.littauer@gmail.com>"
102112
],
103113
"devDependencies": {
104-
"execa": "^5.1.1",
105-
"go-ipfs": "^0.9.1",
106-
"ipfs": "^0.59.0",
107-
"ipfs-http-client": "^53.0.0"
114+
"go-ipfs": "^0.11.0",
115+
"ipfs": "^0.61.0",
116+
"ipfs-http-client": "^55.0.0"
108117
}
109118
}

‎scripts/custom-runtime.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ if [ ! -d /tmp/go-ipfs ]; then
2525
git clone https://github.com/ipfs/go-ipfs.git
2626
cd go-ipfs
2727
# set implementation to specific commit
28-
git switch master # https://github.com/ipfs/go-ipfs/pull/8563 got merged, lets roll with master until go-ipfs 0.11.0-rc1
28+
git checkout CHANGEME_GO
2929
make build
3030
fi
3131
fi

‎scripts/setup-libp2p-relay-daemon.js

+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
#!/usr/bin/env node
2+
3+
// this script will download the libp2p-relay-daemon binary
4+
// for windows/macos/linux. based on parts of https://github.com/ipfs/npm-go-ipfs
5+
6+
import goenv from 'go-platform'
7+
import gunzip from 'gunzip-maybe'
8+
import got from 'got'
9+
import path from 'path'
10+
import tarFS from 'tar-fs'
11+
import unzip from 'unzip-stream'
12+
import cachedir from 'cachedir'
13+
import fs from 'fs'
14+
import os from 'os'
15+
import hasha from 'hasha'
16+
17+
// libp2p-relay-daemon version from https://dist.ipfs.io/libp2p-relay-daemon/
18+
const LIBP2P_RELAY_DAEMON_VERSION = 'v0.1.0'
19+
20+
/**
21+
* avoid expensive fetch if file is already in cache
22+
* @param {string} url
23+
*/
24+
async function cachingFetchAndVerify (url) {
25+
const cacheDir = process.env.NPM_GO_LIBP2P_RELAY_DAEMON_CACHE || cachedir('npm-go-libp2p-relay-daemon')
26+
const filename = url.split('/').pop()
27+
28+
if (!filename) {
29+
throw new Error('Invalid URL')
30+
}
31+
32+
const cachedFilePath = path.join(cacheDir, filename)
33+
const cachedHashPath = `${cachedFilePath}.sha512`
34+
35+
if (!fs.existsSync(cacheDir)) {
36+
fs.mkdirSync(cacheDir, { recursive: true })
37+
}
38+
if (!fs.existsSync(cachedFilePath)) {
39+
console.info(`Downloading ${url} to ${cacheDir}`)
40+
// download file
41+
fs.writeFileSync(cachedFilePath, await got(url).buffer())
42+
console.info(`Downloaded ${url}`)
43+
44+
// ..and checksum
45+
console.info(`Downloading ${filename}.sha512`)
46+
fs.writeFileSync(cachedHashPath, await got(`${url}.sha512`).buffer())
47+
console.info(`Downloaded ${filename}.sha512`)
48+
} else {
49+
console.info(`Found ${cachedFilePath}`)
50+
}
51+
52+
console.info(`Verifying ${filename}.sha512`)
53+
54+
const digest = Buffer.alloc(128)
55+
const fd = fs.openSync(cachedHashPath, 'r')
56+
fs.readSync(fd, digest, 0, digest.length, 0)
57+
fs.closeSync(fd)
58+
const expectedSha = digest.toString('utf8')
59+
const calculatedSha = await hasha.fromFile(cachedFilePath, { encoding: 'hex', algorithm: 'sha512' })
60+
if (calculatedSha !== expectedSha) {
61+
console.log(`Expected SHA512: ${expectedSha}`)
62+
console.log(`Calculated SHA512: ${calculatedSha}`)
63+
throw new Error(`SHA512 of ${cachedFilePath}' (${calculatedSha}) does not match expected value from ${cachedFilePath}.sha512 (${expectedSha})`)
64+
}
65+
console.log(`OK (${expectedSha})`)
66+
67+
return fs.createReadStream(cachedFilePath)
68+
}
69+
70+
/**
71+
* @param {string} version
72+
* @param {string} platform
73+
* @param {string} arch
74+
* @param {string} distUrl
75+
*/
76+
async function getDownloadURL (version, platform, arch, distUrl) {
77+
const data = await got(`${distUrl}/libp2p-relay-daemon/${version}/dist.json`).json()
78+
79+
if (!data.platforms[platform]) {
80+
throw new Error(`No binary available for platform '${platform}'`)
81+
}
82+
83+
if (!data.platforms[platform].archs[arch]) {
84+
throw new Error(`No binary available for arch '${arch}'`)
85+
}
86+
87+
const link = data.platforms[platform].archs[arch].link
88+
return `${distUrl}/libp2p-relay-daemon/${version}${link}`
89+
}
90+
91+
/**
92+
* @param {string} url
93+
* @param {string} installPath
94+
* @param {import('stream').Readable} stream
95+
*/
96+
function unpack (url, installPath, stream) {
97+
return new Promise((resolve, reject) => {
98+
if (url.endsWith('.zip')) {
99+
return stream.pipe(
100+
unzip
101+
.Extract({ path: installPath })
102+
.on('close', resolve)
103+
.on('error', reject)
104+
)
105+
}
106+
107+
return stream
108+
.pipe(gunzip())
109+
.pipe(
110+
tarFS
111+
.extract(installPath)
112+
.on('finish', resolve)
113+
.on('error', reject)
114+
)
115+
})
116+
}
117+
118+
/**
119+
* @param {object} options
120+
* @param {string} options.version
121+
* @param {string} options.platform
122+
* @param {string} options.arch
123+
* @param {string} options.installPath
124+
* @param {string} options.distUrl
125+
*/
126+
async function download ({ version, platform, arch, installPath, distUrl }) {
127+
const url = await getDownloadURL(version, platform, arch, distUrl)
128+
const data = await cachingFetchAndVerify(url)
129+
130+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'tmp-libp2p-relay-daemon'))
131+
await unpack(url, tmpDir, data)
132+
133+
const filename = `libp2p-relay-daemon${platform === 'windows' ? '.exe' : ''}`
134+
const tmpPath = path.join(tmpDir, 'libp2p-relay-daemon', filename)
135+
const finalPath = path.join(installPath, filename)
136+
try {
137+
// remove old binary, just to be sure we always use the correct version
138+
if (fs.accessSync(finalPath)) {
139+
fs.rmSync(finalPath, { recursive: true })
140+
}
141+
} catch (e) {}
142+
fs.cpSync(tmpPath, finalPath)
143+
fs.rmSync(tmpDir, { recursive: true })
144+
console.info(`Unpacked binary placed in ${finalPath}`)
145+
146+
return finalPath
147+
}
148+
149+
download({
150+
version: LIBP2P_RELAY_DAEMON_VERSION,
151+
platform: process.env.TARGET_OS || goenv.GOOS,
152+
arch: process.env.TARGET_ARCH || goenv.GOARCH,
153+
distUrl: process.env.GO_IPFS_DIST_URL || 'https://dist.ipfs.io',
154+
installPath: path.resolve('scripts')
155+
})
156+
.catch(err => {
157+
console.error(err)
158+
process.exit(1)
159+
})

‎scripts/setup-relayd.sh

-17
This file was deleted.

‎test/ipns-pubsub.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ const namespace = '/record/'
2222

2323
const ipfsRef = '/ipfs/QmPFVLPmp9zv5Z5KUqLhe2EivAGccQW2r7M7jhVJGLZoZU'
2424

25-
// TODO: unskip after https://github.com/ipfs/js-ipfs/pull/3922 and https://github.com/ipfs/go-ipfs/pull/8183 both ship
26-
describe.skip('ipns-pubsub', function () {
25+
describe('ipns-pubsub', function () {
2726
let nodes = []
2827
let factory
2928

‎test/kad-dht.js

+296-42
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,326 @@
1+
/* eslint max-nested-callbacks: ["error", 6] */
12
/* eslint-env mocha */
23

3-
import randomBytes from 'iso-random-stream/src/random.js'
4-
import concat from 'it-concat'
54
import { expect } from 'aegir/utils/chai.js'
65
import { daemonFactory } from './utils/daemon-factory.js'
6+
import delay from 'delay'
7+
import defer from 'p-defer'
8+
import { fromString as uint8ArrayFromString } from 'uint8arrays'
9+
import { isNode } from 'wherearewe'
10+
import toBuffer from 'it-to-buffer'
711

8-
describe.skip('kad-dht', () => {
9-
let factory
12+
const getConfig = (bootstrap) => ({
13+
Bootstrap: bootstrap,
14+
Routing: {
15+
Type: 'dhtserver'
16+
}
17+
})
1018

11-
before(async () => {
12-
factory = await daemonFactory()
19+
const spawnGoDaemon = (factory, bootstrap = []) => {
20+
return factory.spawn({
21+
type: 'go',
22+
test: true,
23+
ipfsOptions: {
24+
config: getConfig(bootstrap)
25+
}
1326
})
27+
}
1428

15-
after(() => factory.clean())
29+
const spawnJsDaemon = (factory, bootstrap = []) => {
30+
return factory.spawn({
31+
type: 'js',
32+
test: true,
33+
ipfsOptions: {
34+
config: getConfig(bootstrap)
35+
}
36+
})
37+
}
1638

17-
describe('a JS node in the land of Go', () => {
18-
let jsD
19-
let goD1
20-
let goD2
21-
let goD3
39+
const spawnDaemon = async function (factory, fn) {
40+
const daemon = await fn(factory)
41+
const id = await daemon.api.id()
2242

23-
before(async () => {
24-
[goD1, goD2, goD3, jsD] = await Promise.all([
25-
factory.spawn({ type: 'go' }),
26-
factory.spawn({ type: 'go' }),
27-
factory.spawn({ type: 'go' }),
28-
factory.spawn({ type: 'js' })
29-
])
43+
return {
44+
api: daemon.api, id
45+
}
46+
}
47+
48+
const getNodeAddr = async (node) => {
49+
const res = await node.api.id()
50+
expect(res.id).to.exist()
51+
52+
return res.addresses[0]
53+
}
54+
55+
const addFileAndCat = async (addDaemon, catDaemons, options = {}) => {
56+
const data = uint8ArrayFromString(`some-data-${Math.random()}`)
57+
const { cid } = await addDaemon.api.add(data)
58+
59+
await Promise.all(
60+
catDaemons.map(async daemon => {
61+
const res = await toBuffer(daemon.api.cat(cid, options))
62+
63+
expect(res).to.equalBytes(data)
3064
})
65+
)
66+
}
3167

32-
after(() => factory.clean())
68+
const createNetwork = function (name, createNodes, tests) {
69+
describe(name, function () {
70+
const nodes = defer()
71+
let factory
3372

34-
it('make connections', async () => {
35-
await Promise.all([
36-
jsD.api.swarm.connect(goD1.api.peerId.addresses[0]),
37-
goD1.api.swarm.connect(goD2.api.peerId.addresses[0]),
38-
goD2.api.swarm.connect(goD3.api.peerId.addresses[0])
39-
])
73+
before(async function () {
74+
factory = await daemonFactory()
75+
nodes.resolve(await createNodes(factory))
4076
})
4177

42-
it('one hop', async () => {
43-
const data = randomBytes(9001)
78+
after(async function () {
79+
await factory.clean()
80+
})
81+
82+
tests(nodes.promise)
83+
})
84+
}
85+
86+
const createBootstrappedNetwork = function (name, createBootstrapper, createNodes) {
87+
createNetwork(name, async factory => {
88+
const bootstrapper = await createBootstrapper(factory)
89+
const bootstrapAddr = await getNodeAddr(bootstrapper)
90+
const nodes = await createNodes(factory, bootstrapAddr)
91+
92+
while (true) {
93+
const peers = await bootstrapper.api.swarm.peers()
4494

45-
const { cid } = await goD1.api.add(data)
46-
const file = await concat(jsD.api.cat(cid))
95+
if (peers.length === nodes.length) {
96+
break
97+
}
4798

48-
expect(file.slice()).to.be.eql(data)
99+
await delay(500)
100+
}
101+
102+
return nodes
103+
}, (nodes) => {
104+
it('should get from the network after being added', async function () {
105+
const [add, ...cat] = await nodes
106+
await addFileAndCat(add, cat)
49107
})
108+
})
109+
}
110+
111+
const createLinearNetwork = function (name, createNodes) {
112+
createNetwork(name, async factory => {
113+
const [node0, node1, node2, node3] = await createNodes(factory)
114+
115+
/*
116+
* Make connections between nodes
117+
* +-+ +-+
118+
* |0+-----> |1|
119+
* +++ +++
120+
* ^ |
121+
* | |
122+
* | v
123+
* +++ +++
124+
* |3| |2|
125+
* +-+ +-+
126+
*/
127+
await node3.api.swarm.connect(node0.id.addresses[0])
128+
await node0.api.swarm.connect(node1.id.addresses[0])
129+
await node1.api.swarm.connect(node2.id.addresses[0])
50130

131+
return [node0, node1, node2, node3]
132+
}, (nodes) => {
133+
it('one hop', async () => {
134+
const [node0, _node1, _node2, node3] = await nodes // eslint-disable-line no-unused-vars
135+
await addFileAndCat(node0, [node3])
136+
})
51137
it('two hops', async () => {
52-
const data = randomBytes(9001)
138+
const [_node0, node1, _node2, node3] = await nodes // eslint-disable-line no-unused-vars
139+
await addFileAndCat(node1, [node3])
140+
})
141+
it('three hops', async () => {
142+
const [_node0, _node1, node2, node3] = await nodes // eslint-disable-line no-unused-vars
143+
await addFileAndCat(node2, [node3])
144+
})
145+
})
146+
}
147+
148+
const createDisjointNetwork = function (name, createNodes) {
149+
createNetwork(name, async factory => {
150+
const [node0, node1, node2, node3, node4, node5] = await createNodes(factory)
151+
152+
// Make connections between nodes
153+
154+
// 0 -> 1 -> 2
155+
await node0.api.swarm.connect(node1.id.addresses[0])
156+
await node1.api.swarm.connect(node2.id.addresses[0])
157+
158+
// 3 -> 4 -> 5
159+
await node3.api.swarm.connect(node4.id.addresses[0])
160+
await node4.api.swarm.connect(node5.id.addresses[0])
53161

54-
const { cid } = await goD2.api.add(data)
55-
const file = await concat(jsD.api.cat(cid))
162+
return [node0, node1, node2, node3, node4, node5]
163+
}, (nodes) => {
164+
it('join network', async () => {
165+
const [node0, _node1, node2, node3, _node4, node5] = await nodes // eslint-disable-line no-unused-vars
56166

57-
expect(file.slice()).to.be.eql(data)
167+
// nodes at opposite ends should not find content
168+
await expect(addFileAndCat(node0, [node3], {
169+
timeout: 5000
170+
})).to.eventually.be.rejected()
171+
172+
/*
173+
* Make connections between nodes
174+
* 0 -> 1 -> 2 -> 5 -> 4 -> 3
175+
*/
176+
177+
await node2.api.swarm.connect(node5.id.addresses[0])
178+
179+
// should now succeed
180+
await addFileAndCat(node0, [node3])
58181
})
182+
})
183+
}
59184

60-
it('three hops', async () => {
61-
const data = randomBytes(9001)
185+
describe('kad-dht', function () {
186+
this.timeout(600 * 1000)
62187

63-
const { cid } = await goD3.api.add(data)
64-
const file = await concat(jsD.api.cat(cid))
188+
if (!isNode) {
189+
it.skip('DHT tests are only run on node')
190+
return
191+
}
65192

66-
expect(file.slice()).to.be.eql(data)
193+
describe('kad-dht with a bootstrap node', () => {
194+
createBootstrappedNetwork('a JS network', factory => spawnJsDaemon(factory), (factory, bootstrapAddr) => {
195+
return Promise.all([
196+
spawnJsDaemon(factory, [bootstrapAddr]),
197+
spawnJsDaemon(factory, [bootstrapAddr]),
198+
spawnJsDaemon(factory, [bootstrapAddr])
199+
])
200+
})
201+
202+
createBootstrappedNetwork('a GO network', factory => spawnGoDaemon(factory), (factory, bootstrapAddr) => {
203+
return Promise.all([
204+
spawnGoDaemon(factory, [bootstrapAddr]),
205+
spawnGoDaemon(factory, [bootstrapAddr]),
206+
spawnGoDaemon(factory, [bootstrapAddr])
207+
])
208+
})
209+
210+
createBootstrappedNetwork('a JS bootstrap node in the land of Go', factory => spawnJsDaemon(factory), (factory, bootstrapAddr) => {
211+
return Promise.all([
212+
spawnGoDaemon(factory, [bootstrapAddr]),
213+
spawnGoDaemon(factory, [bootstrapAddr]),
214+
spawnGoDaemon(factory, [bootstrapAddr])
215+
])
216+
})
217+
218+
createBootstrappedNetwork('a Go bootstrap node in the land of JS', factory => spawnGoDaemon(factory), (factory, bootstrapAddr) => {
219+
return Promise.all([
220+
spawnJsDaemon(factory, [bootstrapAddr]),
221+
spawnJsDaemon(factory, [bootstrapAddr]),
222+
spawnJsDaemon(factory, [bootstrapAddr])
223+
])
224+
})
225+
226+
createBootstrappedNetwork('a JS bootstrap node in a hybrid land', factory => spawnJsDaemon(factory), (factory, bootstrapAddr) => {
227+
return Promise.all([
228+
spawnGoDaemon(factory, [bootstrapAddr]),
229+
spawnJsDaemon(factory, [bootstrapAddr]),
230+
spawnGoDaemon(factory, [bootstrapAddr])
231+
])
232+
})
233+
234+
createBootstrappedNetwork('a Go bootstrap node in a hybrid land', factory => spawnGoDaemon(factory), (factory, bootstrapAddr) => {
235+
return Promise.all([
236+
spawnJsDaemon(factory, [bootstrapAddr]),
237+
spawnGoDaemon(factory, [bootstrapAddr]),
238+
spawnJsDaemon(factory, [bootstrapAddr])
239+
])
67240
})
68241
})
69242

70-
describe('a Go node in the land of JS', () => {})
71-
describe('hybrid', () => {})
243+
describe('kad-dht with multiple hops', () => {
244+
createLinearNetwork('a JS node in the land of Go', (factory) => {
245+
return Promise.all([
246+
spawnDaemon(factory, spawnGoDaemon),
247+
spawnDaemon(factory, spawnGoDaemon),
248+
spawnDaemon(factory, spawnGoDaemon),
249+
spawnDaemon(factory, spawnJsDaemon)
250+
])
251+
})
252+
253+
createLinearNetwork('a Go node in the land of JS', (factory) => {
254+
return Promise.all([
255+
spawnDaemon(factory, spawnJsDaemon),
256+
spawnDaemon(factory, spawnJsDaemon),
257+
spawnDaemon(factory, spawnJsDaemon),
258+
spawnDaemon(factory, spawnGoDaemon)
259+
])
260+
})
261+
262+
createLinearNetwork('a hybrid network, cat from GO', (factory) => {
263+
return Promise.all([
264+
spawnDaemon(factory, spawnJsDaemon),
265+
spawnDaemon(factory, spawnGoDaemon),
266+
spawnDaemon(factory, spawnJsDaemon),
267+
spawnDaemon(factory, spawnGoDaemon)
268+
])
269+
})
270+
271+
createLinearNetwork('a hybrid network, cat from JS', (factory) => {
272+
return Promise.all([
273+
spawnDaemon(factory, spawnJsDaemon),
274+
spawnDaemon(factory, spawnGoDaemon),
275+
spawnDaemon(factory, spawnJsDaemon),
276+
spawnDaemon(factory, spawnGoDaemon)
277+
])
278+
})
279+
})
280+
281+
describe('kad-dht across disjoint networks that become joint', () => {
282+
createDisjointNetwork('a GO network', (factory) => {
283+
return Promise.all([
284+
spawnDaemon(factory, spawnGoDaemon),
285+
spawnDaemon(factory, spawnGoDaemon),
286+
spawnDaemon(factory, spawnGoDaemon),
287+
spawnDaemon(factory, spawnGoDaemon),
288+
spawnDaemon(factory, spawnGoDaemon),
289+
spawnDaemon(factory, spawnGoDaemon)
290+
])
291+
})
292+
293+
createDisjointNetwork('a JS network', (factory) => {
294+
return Promise.all([
295+
spawnDaemon(factory, spawnJsDaemon),
296+
spawnDaemon(factory, spawnJsDaemon),
297+
spawnDaemon(factory, spawnJsDaemon),
298+
spawnDaemon(factory, spawnJsDaemon),
299+
spawnDaemon(factory, spawnJsDaemon),
300+
spawnDaemon(factory, spawnJsDaemon)
301+
])
302+
})
303+
304+
createDisjointNetwork('a hybrid network, cat from GO', (factory) => {
305+
return Promise.all([
306+
spawnDaemon(factory, spawnGoDaemon),
307+
spawnDaemon(factory, spawnJsDaemon),
308+
spawnDaemon(factory, spawnGoDaemon),
309+
spawnDaemon(factory, spawnJsDaemon),
310+
spawnDaemon(factory, spawnGoDaemon),
311+
spawnDaemon(factory, spawnJsDaemon)
312+
])
313+
})
314+
315+
createDisjointNetwork('a hybrid network, cat from JS', (factory) => {
316+
return Promise.all([
317+
spawnDaemon(factory, spawnJsDaemon),
318+
spawnDaemon(factory, spawnGoDaemon),
319+
spawnDaemon(factory, spawnJsDaemon),
320+
spawnDaemon(factory, spawnGoDaemon),
321+
spawnDaemon(factory, spawnJsDaemon),
322+
spawnDaemon(factory, spawnGoDaemon)
323+
])
324+
})
325+
})
72326
})

‎test/pubsub.js

+28-3
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ const daemonOptions = {
2727

2828
const timeout = 20e3
2929

30-
// TODO: unskip after https://github.com/ipfs/js-ipfs/pull/3922 and https://github.com/ipfs/go-ipfs/pull/8183 both ship
31-
describe.skip('pubsub', function () {
30+
describe('pubsub', function () {
3231
this.timeout(60 * 1000)
3332

3433
const tests = {
@@ -100,7 +99,7 @@ describe.skip('pubsub', function () {
10099
})
101100

102101
it('should exchange non ascii data', function () {
103-
const data = uint8ArrayFromString('你好世界')
102+
const data = uint8ArrayFromString('你好世界 zażółć gęślą jaźń')
104103
const topic = 'pubsub-non-ascii'
105104

106105
const subscriber = () => new Promise((resolve) => {
@@ -150,6 +149,32 @@ describe.skip('pubsub', function () {
150149
publisher()
151150
])
152151
})
152+
153+
it('should exchange data over a topic with unicode and newlines', function () {
154+
const data = uint8ArrayFromString('你好世界\nzażółć\r\ngęślą\njaźń')
155+
const topic = 'pubsub\n你好世界\r\njaźń'
156+
157+
const subscriber = () => new Promise((resolve) => {
158+
daemon2.api.pubsub.subscribe(topic, (msg) => {
159+
expect(uint8ArrayEquals(data, msg.data)).to.be.true()
160+
expect(msg).to.have.property('seqno')
161+
expect(msg.seqno).to.be.an.instanceof(Uint8Array)
162+
expect(msg).to.have.property('topicIDs').and.to.include(topic)
163+
expect(msg).to.have.property('from', daemon1.api.peerId.id)
164+
resolve()
165+
})
166+
})
167+
168+
const publisher = async () => {
169+
await waitForTopicPeer(topic, daemon2.api.peerId, daemon1)
170+
await daemon1.api.pubsub.publish(topic, data)
171+
}
172+
173+
return Promise.all([
174+
subscriber(),
175+
publisher()
176+
])
177+
})
153178
})
154179
})
155180
})

‎test/utils/circuit.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,6 @@ export async function connect (nodeA, nodeB, relay, timeout = 1000) {
231231

232232
export function connWithTimeout (timeout) {
233233
return (nodeA, nodeB, relay) => {
234-
connect(nodeA, nodeB, relay, timeout)
234+
return connect(nodeA, nodeB, relay, timeout)
235235
}
236236
}

‎test/utils/relayd.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import isNode from 'detect-node'
22
import fs from 'fs'
3+
import path from 'path'
34
import { command } from 'execa'
5+
import goenv from 'go-platform'
6+
const platform = process.env.TARGET_OS || goenv.GOOS
47

58
// augumentWithRelayd is the glue code that makes running relayd-based relay
69
// possible without changing too much in existing tests. We keep one instance
@@ -12,7 +15,10 @@ export async function getRelayV (version, factory) {
1215
if (relays.has(version)) return relays.get(version)
1316
if (process.env.DEBUG) console.log(`Starting relayd_v${version}..`) // eslint-disable-line no-console
1417
if (version < 1 || version > 2) throw new Error('Unsupported circuit relay version')
15-
const relayd = command(`go-libp2p-relay-daemon/relayd -config scripts/relayd_v${version}.config.json -id scripts/relayd_v${version}.identity`)
18+
const binaryPath = path.join('scripts', `libp2p-relay-daemon${platform === 'windows' ? '.exe' : ''}`)
19+
const configPath = path.join('scripts', `relayd_v${version}.config.json`)
20+
const identityPath = path.join('scripts', `relayd_v${version}.identity`)
21+
const relayd = command(`${binaryPath} -config ${configPath} -id ${identityPath}`)
1622
let id
1723
for await (const line of relayd.stdout) {
1824
const text = line.toString()
@@ -22,7 +28,7 @@ export async function getRelayV (version, factory) {
2228
id = text.split('I am')[1].split('\n')[0].trim()
2329
}
2430
}
25-
const config = JSON.parse(fs.readFileSync(`scripts/relayd_v${version}.config.json`))
31+
const config = JSON.parse(fs.readFileSync(configPath))
2632
const result = {
2733
relayd,
2834
// Mock: make it look like other things returned by ipfsd-ctl to reuse existing code.

0 commit comments

Comments
 (0)
This repository has been archived.