feat(interop): add js-libp2p v0.44 (#171)

Copy of `multidim-interop/impl/js/v0.42` plus version adjustments + reenable
WebRTC (see https://github.com/libp2p/test-plans/pull/160).
This commit is contained in:
Max Inden 2023-05-05 08:44:42 +02:00 committed by GitHub
parent ec279581b8
commit a2235a0d55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 42919 additions and 0 deletions

View File

@ -0,0 +1,82 @@
import { createClient } from 'redis'
import http from "http"
const redis_addr = process.env.redis_addr || 'redis:6379'
/** @type {import('aegir/types').PartialOptions} */
export default {
test: {
browser: {
config: {
// Ignore self signed certificates
browserContextOptions: { ignoreHTTPSErrors: true }
}
},
async before() {
const redisClient = createClient({
url: `redis://${redis_addr}`
})
redisClient.on('error', (err) => console.error(`Redis Client Error: ${err}`))
await redisClient.connect()
const requestListener = async function (req, res) {
const requestJSON = await new Promise(resolve => {
let body = ""
req.on('data', function (data) {
body += data;
});
req.on('end', function () {
resolve(JSON.parse(body))
});
})
try {
const redisRes = await redisClient.sendCommand(requestJSON)
if (redisRes === null) {
throw new Error("redis sent back null")
}
res.writeHead(200, {
'Access-Control-Allow-Origin': '*'
})
res.end(JSON.stringify(redisRes))
} catch (err) {
console.error("Error in redis command:", err)
res.writeHead(500, {
'Access-Control-Allow-Origin': '*'
})
res.end(err.toString())
return
}
};
const proxyServer = http.createServer(requestListener);
await new Promise(resolve => { proxyServer.listen(0, "localhost", () => { resolve() }); })
return {
redisClient,
proxyServer: proxyServer,
env: {
...process.env,
proxyPort: proxyServer.address().port
}
}
},
async after(_, { proxyServer, redisClient }) {
await new Promise(resolve => {
proxyServer.close(() => resolve());
})
try {
// We don't care if this fails
await redisClient.disconnect()
} catch { }
}
},
build: {
bundlesizeMax: '18kB'
}
}

View File

@ -0,0 +1 @@
node_modules/

View File

@ -0,0 +1,3 @@
dist
node-image.json
chromium-image.json

View File

@ -0,0 +1,6 @@
# syntax=docker/dockerfile:1
ARG BASE_IMAGE
FROM $BASE_IMAGE
ENTRYPOINT [ "npm", "test", "--", "--build", "false", "--types", "false", "-t", "browser" ]

View File

@ -0,0 +1,21 @@
# syntax=docker/dockerfile:1
# Using playwright so that we have the same base across NodeJS + Browser tests
FROM mcr.microsoft.com/playwright
WORKDIR /app
COPY package*.json ./
RUN npm ci
# Install browsers, Needed for the browser tests, but we do it here so we have the same base
RUN ./node_modules/.bin/playwright install
COPY tsconfig.json .
COPY .aegir.js .
COPY test ./test
COPY src ./src
RUN npm run build
ENTRYPOINT [ "npm", "test", "--", "--build", "false", "--types", "false", "-t", "node" ]

View File

@ -0,0 +1,23 @@
image_name := js-v0.44
TEST_SOURCES := $(wildcard test/*.ts)
all: chromium-image.json node-image.json
chromium-image.json: node-image.json
docker build -t chromium-${image_name} -f ChromiumDockerfile --build-arg="BASE_IMAGE=node-${image_name}" .
docker image inspect chromium-${image_name} -f "{{.Id}}" | \
xargs -I {} echo "{\"imageID\": \"{}\"}" > $@
node-image.json: image.json
docker image tag $$(cat image.json | jq -r '.imageID') node-${image_name}
cp image.json node-image.json
image.json: Dockerfile $(TEST_SOURCES) package.json package-lock.json .aegir.js
IMAGE_NAME=node-${image_name} ../../../dockerBuildWrapper.sh -f Dockerfile .
docker image inspect node-${image_name} -f "{{.Id}}" | \
xargs -I {} echo "{\"imageID\": \"{}\"}" > $@
.PHONY: clean
clean:
rm *image.json

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
{
"name": "multidim-interop",
"private": true,
"version": "1.0.0",
"description": "Multidimension Interop Test",
"type": "module",
"main": "index.js",
"author": "Glen De Cauwsemaecker <glen@littlebearlabs.io> / @marcopolo",
"license": "MIT",
"engines": {
"node": ">=18"
},
"scripts": {
"start": "node index.js",
"build": "aegir build",
"test": "aegir test"
},
"dependencies": {
"@chainsafe/libp2p-noise": "^11.0.0",
"@chainsafe/libp2p-yamux": "^3.0.5",
"@libp2p/mplex": "^7.1.1",
"@libp2p/tcp": "^6.0.8",
"@libp2p/webrtc": "^1.1.2",
"@libp2p/websockets": "^5.0.4",
"@libp2p/webtransport": "^1.0.7",
"@multiformats/mafmt": "^12.1.0",
"@multiformats/multiaddr": "^12.1.1",
"libp2p": "^0.44.0",
"node-fetch": "^3.3.0",
"redis": "4.5.1"
},
"browser": {
"@libp2p/tcp": false
},
"devDependencies": {
"aegir": "^38.1.0",
"standard": "^17.0.0",
"typescript": "^4.9.4"
}
}

View File

@ -0,0 +1,3 @@
console.log("Everything is defined in the test folder")
export { }

View File

@ -0,0 +1,155 @@
/* eslint-disable no-console */
/* eslint-env mocha */
import { } from 'aegir/chai'
import { createLibp2p, Libp2pOptions } from 'libp2p'
import { webTransport } from '@libp2p/webtransport'
import { tcp } from '@libp2p/tcp'
import { webSockets } from '@libp2p/websockets'
import { noise } from '@chainsafe/libp2p-noise'
import { mplex } from '@libp2p/mplex'
import { yamux } from '@chainsafe/libp2p-yamux'
import { multiaddr } from '@multiformats/multiaddr'
import { webRTCDirect } from '@libp2p/webrtc'
async function redisProxy(commands: any[]): Promise<any> {
const res = await fetch(`http://localhost:${process.env.proxyPort}/`, { body: JSON.stringify(commands), method: "POST" })
if (!res.ok) {
throw new Error("Redis command failed")
}
return await res.json()
}
describe('ping test', () => {
it('should ping', async () => {
const TRANSPORT = process.env.transport
const SECURE_CHANNEL = process.env.security
const MUXER = process.env.muxer
const isDialer = process.env.is_dialer === "true"
const IP = process.env.ip || "0.0.0.0"
const timeoutSecs: string = process.env.test_timeout_secs || "180"
const options: Libp2pOptions = {
start: true
}
switch (TRANSPORT) {
case 'tcp':
options.transports = [tcp()]
options.addresses = {
listen: isDialer ? [] : [`/ip4/${IP}/tcp/0`]
}
break
case 'webtransport':
options.transports = [webTransport()]
if (!isDialer) {
throw new Error("WebTransport is not supported as a listener")
}
break
case 'webrtc-direct':
options.transports = [webRTCDirect()]
options.addresses = {
listen: isDialer ? [] : [`/ip4/${IP}/udp/0/webrtc-direct`]
}
break
case 'ws':
options.transports = [webSockets()]
options.addresses = {
listen: isDialer ? [] : [`/ip4/${IP}/tcp/0/ws`]
}
break
case 'wss':
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = "0"
options.transports = [webSockets()]
options.addresses = {
listen: isDialer ? [] : [`/ip4/${IP}/tcp/0/wss`]
}
break
default:
throw new Error(`Unknown transport: ${TRANSPORT}`)
}
let skipSecureChannel = false
let skipMuxer = false
switch (TRANSPORT) {
case 'webtransport':
case 'webrtc-direct':
skipSecureChannel = true
skipMuxer = true
}
if (!skipSecureChannel) {
switch (SECURE_CHANNEL) {
case 'noise':
options.connectionEncryption = [noise()]
break
case 'quic':
options.connectionEncryption = [noise()]
break
default:
throw new Error(`Unknown secure channel: ${SECURE_CHANNEL}`)
}
} else {
// Libp2p requires at least one encryption module. Even if unused.
options.connectionEncryption = [noise()]
}
if (!skipMuxer) {
switch (MUXER) {
case 'mplex':
options.streamMuxers = [mplex()]
break
case 'yamux':
options.streamMuxers = [yamux()]
break
case 'quic':
break
default:
throw new Error(`Unknown muxer: ${MUXER}`)
}
}
const node = await createLibp2p(options)
try {
if (isDialer) {
var otherMa = (await redisProxy(["BLPOP", "listenerAddr", timeoutSecs]).catch(err => { throw new Error("Failed to wait for listener") }))[1]
// Hack until these are merged:
// - https://github.com/multiformats/js-multiaddr/pull/312
// - https://github.com/multiformats/js-multiaddr-to-uri/pull/120
otherMa = otherMa.replace("/tls/ws", "/wss")
otherMa = otherMa.replace("/ip4/192.168.5.124", "/dns4/localhost")
console.error(`node ${node.peerId} pings: ${otherMa}`)
const handshakeStartInstant = Date.now()
await node.dial(multiaddr(otherMa))
const pingRTT = await node.ping(multiaddr(otherMa))
const handshakePlusOneRTT = Date.now() - handshakeStartInstant
console.log(JSON.stringify({
handshakePlusOneRTTMillis: handshakePlusOneRTT,
pingRTTMilllis: pingRTT
}))
} else {
const multiaddrs = node.getMultiaddrs().map(ma => ma.toString()).filter(maString => !maString.includes("127.0.0.1"))
console.error("My multiaddrs are", multiaddrs)
// Send the listener addr over the proxy server so this works on both the Browser and Node
await redisProxy(["RPUSH", "listenerAddr", multiaddrs[0]])
// Wait
await new Promise(resolve => setTimeout(resolve, 1000 * parseInt(timeoutSecs, 10)))
}
} catch (err) {
// Show all errors in an aggregated error
if (err instanceof AggregateError) {
console.error(`unexpected exception in ping test: ${err}\n Errors:`, err.errors)
} else {
console.error(`unexpected exception in ping test:`, err)
}
throw err
} finally {
try {
// We don't care if this fails
await node.stop()
} catch { }
}
})
})

View File

@ -0,0 +1,10 @@
{
"extends": "aegir/src/config/tsconfig.aegir.json",
"compilerOptions": {
"outDir": "dist"
},
"include": [
"src",
"test"
]
}

View File

@ -10,9 +10,11 @@ import rustv050 from "./impl/rust/v0.50/image.json"
import rustv051 from "./impl/rust/v0.51/image.json"
import jsV041 from "./impl/js/v0.41/node-image.json"
import jsV042 from "./impl/js/v0.42/node-image.json"
import jsV044 from "./impl/js/v0.44/node-image.json"
import nimv10 from "./impl/nim/v1.0/image.json"
import chromiumJsV041 from "./impl/js/v0.41/chromium-image.json"
import chromiumJsV042 from "./impl/js/v0.42/chromium-image.json"
import chromiumJsV044 from "./impl/js/v0.44/chromium-image.json"
import zigv001 from "./impl/zig/v0.0.1/image.json"
export type Version = {
@ -68,6 +70,13 @@ export const versions: Array<Version> = [
secureChannels: ["noise"],
muxers: ["mplex", "yamux"],
},
{
id: "js-v0.44.0",
containerImageID: jsV044.imageID,
transports: ["tcp", "ws", { name: "wss", onlyDial: true }],
secureChannels: ["noise"],
muxers: ["mplex", "yamux"],
},
{
id: "chromium-js-v0.41.0",
containerImageID: chromiumJsV041.imageID,
@ -82,6 +91,13 @@ export const versions: Array<Version> = [
secureChannels: ["noise"],
muxers: ["mplex", "yamux"]
},
{
id: "chromium-js-v0.44.0",
containerImageID: chromiumJsV044.imageID,
transports: [{ name: "webtransport", onlyDial: true }, { name: "wss", onlyDial: true }, { name: "webrtc-direct", onlyDial: true }],
secureChannels: ["noise"],
muxers: ["mplex", "yamux"],
},
{
id: "go-v0.27.1",
containerImageID: gov027.imageID,