Skip to content

Commit

Permalink
Test JS to Go connections with both RSA and ECDSA keys
Browse files Browse the repository at this point in the history
  • Loading branch information
aknuds1 committed Jul 11, 2019
1 parent 864265c commit 4996f42
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 68 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@
},
"homepage": "https://github.com/libp2p/interop#readme",
"devDependencies": {
"@arve.knudsen/libp2p-daemon": "^0.2.6",
"aegir": "^19.0.3",
"chai": "^4.2.0",
"chai-bytes": "~0.1.2",
"chai-checkmark": "^1.0.1",
"cross-env": "^5.2.0",
"dirty-chai": "^2.0.1",
"go-libp2p-dep": "~0.1.0",
"libp2p-daemon": "~0.2.1",
"@arve.knudsen/go-libp2p-dep": "~0.2.2",
"libp2p-daemon-client": "~0.2.1",
"multiaddr": "^6.0.6",
"rimraf": "^2.6.3"
Expand Down
33 changes: 21 additions & 12 deletions src/daemon.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const fs = require('fs')
const path = require('path')
const rimraf = require('rimraf')

const Client = require('libp2p-daemon-client')
const Client = require('@arve.knudsen/libp2p-daemon-client')
const { getMultiaddr, isWindows } = require('./utils')

// process path
Expand All @@ -15,27 +15,29 @@ const processPath = process.cwd()
// go-libp2p defaults
const goDaemon = {
defaultAddr: getMultiaddr('/tmp/p2pd-go.sock'),
bin: path.join('go-libp2p-dep', 'go-libp2p', isWindows ? 'p2pd.exe' : 'p2pd')
bin: path.join('@arve.knudsen/go-libp2p-dep', 'go-libp2p', isWindows ? 'p2pd.exe' : 'p2pd')
}

// js-libp2p defaults
const jsDaemon = {
defaultAddr: getMultiaddr('/tmp/p2pd-js.sock'),
bin: path.join('libp2p-daemon', 'src', 'cli', 'bin.js')
bin: path.join('@arve.knudsen/libp2p-daemon', 'src', 'cli', 'bin.js')
}

class Daemon {
/**
* @constructor
* @param {String} type daemon implementation type ("go" or "js")
* @param {String} spec daemon implementation spec (type "go" or "js")
* @param {Multiaddr} addr multiaddr for the client to connect to
* @param {Number} port port for the client to connect to
*/
constructor (type, addr, port) {
constructor (spec, addr, port) {
const { type, keyFile } = spec
assert(type === 'go' || type === 'js', 'invalid type received. Should be "go" or "js"')

this._client = undefined
this._type = type
this._keyFile = keyFile
this._binPath = this._getBinPath(type)
this._addr = addr && getMultiaddr(addr, port)

Expand Down Expand Up @@ -100,29 +102,36 @@ class Daemon {
_startDaemon (options) {
return new Promise((resolve, reject) => {
let execOptions
const addr = this._addr.toString()

// TODO refactor this once we daemon supports a json config
if (this._type === 'go') {
execOptions = ['-listen', this._addr]
execOptions = ['-listen', addr, '-enableInlining=false']

options.dht && execOptions.push('-dht')
options.pubsub && execOptions.push('-pubsub')
} else {
execOptions = ['--listen', this._addr]
execOptions = ['--listen', addr]

options.dht && execOptions.push('--dht')
options.pubsub && execOptions.push('--pubsub')
}
if ((this._keyFile || '') !== '') {
execOptions.push(`--id=${this._keyFile}`)
}

const daemon = execa(this._binPath, execOptions)

daemon.stdout.once('data', () => {
return resolve()
resolve()
})

daemon.stderr.on('data', (data) => {
if (!data.toString().includes('Warning')) {
return reject(data.toString())
daemon.on('exit', (code, signal) => {
if (code !== 0) {
reject(new Error(`daemon exited with status code ${code}`))
} else if ((signal || '') !== '') {
reject(new Error(`daemon exited due to signal ${signal}`))
} else {
resolve()
}
})
})
Expand Down
100 changes: 69 additions & 31 deletions test/connect/js2go.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,84 @@ const expect = chai.expect

const spawnDaemons = require('../utils/spawnDaemons')

describe('connect', () => {
let daemons
const beforeConnect = (ctx, keyType) => {
ctx.timeout(20 * 1000)

// Start Daemons
before(async function () {
this.timeout(20 * 1000)
return spawnDaemons(2, [{ type: 'js', keyType }, { type: 'go', keyType }])
}

daemons = await spawnDaemons(2, ['js', 'go'])
})
const afterConnect = async (daemons) => {
if (daemons == null) {
return
}

// Stop daemons
after(async function () {
await Promise.all(
daemons.map((daemon) => daemon.stop())
)
})
await Promise.all(
daemons.map(async (daemon) => {
// Ignore errors
try {
await daemon.stop()
} catch (_) {
}
})
)
}

const performTest = async (ctx, daemons) => {
ctx.timeout(10 * 1000)

const identifyJs = await daemons[0].client.identify()
const identifyGo = await daemons[1].client.identify()

// verify connected peers
const knownPeersBeforeConnectJs = await daemons[0].client.listPeers()
expect(knownPeersBeforeConnectJs).to.have.lengthOf(0)

const knownPeersBeforeConnectGo = await daemons[1].client.listPeers()
expect(knownPeersBeforeConnectGo).to.have.lengthOf(0)

it('js peer to go peer', async function () {
this.timeout(10 * 1000)
// connect peers
await daemons[0].client.connect(identifyGo.peerId, identifyGo.addrs)

const identifyJs = await daemons[0].client.identify()
const identifyGo = await daemons[1].client.identify()
// verify connected peers
const knownPeersAfterConnectJs = await daemons[0].client.listPeers()
expect(knownPeersAfterConnectJs).to.have.lengthOf(1)
expect(knownPeersAfterConnectJs[0].toB58String()).to.equal(identifyGo.peerId.toB58String())

// verify connected peers
const knownPeersBeforeConnectJs = await daemons[0].client.listPeers()
expect(knownPeersBeforeConnectJs).to.have.lengthOf(0)
const knownPeersAfterConnectGo = await daemons[1].client.listPeers()
expect(knownPeersAfterConnectGo).to.have.lengthOf(1)
expect(knownPeersAfterConnectGo[0].toB58String()).to.equal(identifyJs.peerId.toB58String())
}

describe('connecting js peer to go peer', () => {
describe('with RSA keys', () => {
let daemons

before(async function () {
daemons = await beforeConnect(this, 'rsa')
})

after(async () => {
await afterConnect(daemons)
})

it('should work', async function () {
await performTest(this, daemons)
})
})

const knownPeersBeforeConnectGo = await daemons[1].client.listPeers()
expect(knownPeersBeforeConnectGo).to.have.lengthOf(0)
describe('with SECP256k1 keys', () => {
let daemons

// connect peers
await daemons[0].client.connect(identifyGo.peerId, identifyGo.addrs)
before(async function () {
daemons = await beforeConnect(this, 'secp256k1')
})

// verify connected peers
const knownPeersAfterConnectJs = await daemons[0].client.listPeers()
expect(knownPeersAfterConnectJs).to.have.lengthOf(1)
expect(knownPeersAfterConnectJs[0].toB58String()).to.equal(identifyGo.peerId.toB58String())
after(async () => {
await afterConnect(daemons)
})

const knownPeersAfterConnectGo = await daemons[1].client.listPeers()
expect(knownPeersAfterConnectGo).to.have.lengthOf(1)
expect(knownPeersAfterConnectGo[0].toB58String()).to.equal(identifyJs.peerId.toB58String())
it('should work', async function () {
await performTest(this, daemons)
})
})
})
Binary file added test/resources/keys/go.rsa.key
Binary file not shown.
1 change: 1 addition & 0 deletions test/resources/keys/go.secp256k1.key
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
 {��ܥg� oT+.�\�L� Y��Jb���G�q7�
Binary file added test/resources/keys/js.rsa.key
Binary file not shown.
1 change: 1 addition & 0 deletions test/resources/keys/js.secp256k1.key
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
 �z�m�/�kPa�ࡓ$�Z���p"�>v��
53 changes: 30 additions & 23 deletions test/utils/spawnDaemons.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,49 @@
'use strict'

const assert = require('assert')
const path = require('path')

const Daemon = require('../../src/daemon')

const startPortNumber = 9000

/**
* @param {number} n number of nodes to spawn
* @param {string|array} type nodes type (default: js)
* @param {string|array} specs node specs (default: 'js')
* @param {Object|array} options daemon options
*/
async function spawnDaemons (n, type = 'js', options) {
async function spawnDaemons (n, specs = 'js', options) {
assert(n, 'spawnDaemons require a number of nodes to start')
assert(validType(n, type), 'spawnDaemons type is not valid')

let types = type

if (!Array.isArray(types)) {
types = new Array(n).fill(type)
if (!Array.isArray(specs)) {
specs = new Array(n).fill(specs)
}
specs = specs.map((spec) => {
if (typeof spec === 'string') {
return {
type: spec
}
}

let daemonOptions = options
return spec
})
validateSpecs(n, specs)

let daemonOptions = options
if (!Array.isArray(daemonOptions)) {
daemonOptions = new Array(n).fill(options)
}

const daemons = []
let daemon

for (let i = 0; i < n; i++) {
daemon = new Daemon(types[i], `/tmp/p2pd-${i}.sock`, startPortNumber + i)
const spec = specs[i]
const keyFile = spec.keyType != null
? path.resolve(__dirname, `../resources/keys/${spec.type}.${spec.keyType}.key`) : null
const daemonSpec = {
type: spec.type,
keyFile
}
const daemon = new Daemon(daemonSpec, `/tmp/p2pd-${i}.sock`, startPortNumber + i)
daemons.push(daemon)
}

Expand All @@ -40,19 +52,14 @@ async function spawnDaemons (n, type = 'js', options) {
return daemons
}

function validType (n, type) {
// validate string type
if (typeof type === 'string' && (type === 'js' || type === 'go')) {
return true
}

// validate array of types
if (Array.isArray(type) && type.length === n &&
!type.filter((t) => (t !== 'go' && t !== 'js')).length) {
return true
}
function validateSpecs (n, specs) {
assert(specs.length === n, 'number of specs must be equal to n')

return false
specs.forEach((spec) => {
assert(spec.type === 'js' || spec.type === 'go', `invalid spec type ${spec.type}`)
assert(spec.keyType == null || spec.keyType === 'rsa' || spec.keyType === 'secp256k1',
`invalid spec key type ${spec.keyType}`)
})
}

module.exports = spawnDaemons

0 comments on commit 4996f42

Please sign in to comment.