Skip to content

Commit 86e947d

Browse files
committed
feat: initial implementation
1 parent f504198 commit 86e947d

29 files changed

+487
-29
lines changed

.gitignore

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
**/node_modules/
2+
**/*.log
3+
test/repo-tests*
4+
**/bundle.js
5+
docs
6+
# Logs
7+
logs
8+
*.log
9+
10+
coverage
11+
12+
# Runtime data
13+
pids
14+
*.pid
15+
*.seed
16+
17+
# Directory for instrumented libs generated by jscoverage/JSCover
18+
lib-cov
19+
20+
# Coverage directory used by tools like istanbul
21+
coverage
22+
23+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24+
.grunt
25+
26+
# node-waf configuration
27+
.lock-wscript
28+
29+
build
30+
31+
# Dependency directory
32+
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
33+
node_modules
34+
35+
lib
36+
dist
37+
test/test-data/go-ipfs-repo/LOCK
38+
test/test-data/go-ipfs-repo/LOG
39+
test/test-data/go-ipfs-repo/LOG.old
40+
41+
# while testing npm5
42+
package-lock.json

.travis.yml

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
language: node_js
2+
cache: npm
3+
stages:
4+
- check
5+
- test
6+
- cov
7+
8+
node_js:
9+
- '10'
10+
11+
os:
12+
- linux
13+
- osx
14+
- windows
15+
16+
matrix:
17+
fast_finish: true
18+
allow_failures:
19+
- os: windows
20+
21+
script: npx nyc -s npm run test:node -- --bail
22+
after_success: npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov
23+
24+
jobs:
25+
include:
26+
- stage: check
27+
script:
28+
- npx aegir commitlint --travis
29+
- npx aegir dep-check
30+
- npm run lint
31+
32+
notifications:
33+
email: false

README.md

+30-23
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,40 @@
1-
# Interoperability Compliance Test Stories for libp2p
1+
# Interoperability Tests for libp2p
22

3-
<a href="http://protocol.ai"><img src="https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square" /></a>
4-
<a href="http://libp2p.io/"><img src="https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square" /></a>
5-
<a href="http://webchat.freenode.net/?channels=%23libp2p"><img src="https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square" /></a>
6-
<a href="https://waffle.io/libp2p/libp2p"><img src="https://img.shields.io/badge/pm-waffle-yellow.svg?style=flat-square" /></a>
3+
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](https://protocol.ai/)
4+
[![](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/)
5+
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23libp2p)
76

8-
> In this repo you will find the [PDD (Protocol Driven Development)](https://github.com/ipfs/pdd) stories that enable you to test a libp2p implementation against other implementations.
7+
> Interoperability tests for libp2p Implementations
98
10-
## ❗️ Important
9+
This repository will be used for interop tests.
1110

12-
**The setup for these tests is still in flux, please make sure to read the latest update at: https://github.com/libp2p/interop/issues/1**
11+
## Lead Maintainer
1312

14-
## PDD Compliance Test Stories
13+
[Vasco Santos](https://github.com/vasco-santos)
1514

16-
Each Test Story has actors and a dramatization.
15+
## Usage
1716

18-
- **Qualitative** - Test Stories that check feature interoperability and compliance.
19-
- [Transports](./PDD-TRANSPORTS.md)
20-
- [Protocol and Stream Multiplexing](./PDD-PROTOCOL-AND-STREAM-MULTIPLEXING.md)
21-
- [Identify](./PDD-IDENTIFY.md)
22-
- [Encrypted Communications](./PDD-ENCRYPTED-COMMUNICATIONS.md)
23-
- [Peer Routing](./PDD-PEER-ROUTING.md)
24-
- [Content Routing](./PDD-CONTENT-ROUTING.md)
25-
- [PubSub](./PDD-PUBSUB.md)
26-
- [Circuit Relay](./PDD-CIRCUIT-RELAY.md)
27-
- [The IPFS bundle](./PDD-THE-IPFS-BUNDLE.md)
28-
- **Quantitative** - Test Stories focused on stress testing the implementations against each other.
29-
- [Thousands of Muxed Streams](./PDD-THOUSANDS-OF-MUXED-STREAMS.md)
30-
- [Hundreds of Peer Connections](./PDD-HUNDREDS-OF-PEER-CONNECTIONS.md)
17+
### Install
18+
19+
```
20+
> git clone git@github.com:libp2p/interop.git
21+
> cd interop
22+
> npm install
23+
```
24+
25+
### Run the tests
26+
27+
```
28+
> npm test
29+
```
30+
31+
### Test with a non yet released version of js-ipfs
32+
33+
TODO
34+
35+
### Test with a non yet released version of go-ipfs
36+
37+
TODO
3138

3239
## Contribute
3340

package.json

+31-6
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,44 @@
11
{
2-
"name": "libp2p-interop",
2+
"name": "interop-libp2p",
33
"version": "0.0.0",
4-
"description": "",
5-
"main": " ",
4+
"description": "Interoperability Tests for libp2p",
5+
"leadMaintainer": "Vasco Santos <santos.vasco10@gmail.com>",
6+
"main": "",
7+
"engines": {
8+
"node": ">=10.0.0",
9+
"npm": ">6.0.0"
10+
},
611
"scripts": {
7-
"test": "echo \"Error: no test specified\" && exit 1"
12+
"lint": "aegir lint",
13+
"test": "cross-env IPFS_REUSEPORT=false aegir test -t node -f test/node.js",
14+
"test:node": "cross-env IPFS_REUSEPORT=false aegir test -t node -f test/node.js",
15+
"test:browser": "cross-env IPFS_REUSEPORT=false aegir test -t browser --no-cors -f test/browser.js"
816
},
917
"repository": {
1018
"type": "git",
1119
"url": "git+https://github.com/libp2p/interop.git"
1220
},
13-
"author": "David Dias <daviddias@ipfs.io>",
21+
"keywords": [
22+
"libp2p"
23+
],
1424
"license": "MIT",
1525
"bugs": {
1626
"url": "https://github.com/libp2p/interop/issues"
1727
},
18-
"homepage": "https://github.com/libp2p/interop#readme"
28+
"homepage": "https://github.com/libp2p/interop#readme",
29+
"devDependencies": {
30+
"aegir": "^17.0.1",
31+
"chai": "^4.2.0",
32+
"chai-checkmark": "^1.0.1",
33+
"cross-env": "^5.2.0",
34+
"dirty-chai": "^2.0.1",
35+
"go-libp2p-dep": "^6.0.30",
36+
"libp2p-daemon": "~0.1.2",
37+
"libp2p-daemon-client": "~0.0.3",
38+
"rimraf": "^2.6.3"
39+
},
40+
"contributors": [],
41+
"dependencies": {
42+
"execa": "^1.0.0"
43+
}
1944
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

PDD-PUBSUB.md pdd/PDD-PUBSUB.md

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

peer-a.json pdd/peer-a.json

File renamed without changes.

peer-b.json pdd/peer-b.json

File renamed without changes.

peer-c.json pdd/peer-c.json

File renamed without changes.

peer-d.json pdd/peer-d.json

File renamed without changes.

peer-e.json pdd/peer-e.json

File renamed without changes.

src/daemon.js

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
'use strict'
2+
3+
const assert = require('assert')
4+
const execa = require('execa')
5+
const fs = require('fs')
6+
const os = require('os')
7+
const path = require('path')
8+
const rimraf = require('rimraf')
9+
10+
const Client = require('libp2p-daemon-client')
11+
const { getSockPath } = require('./utils')
12+
13+
const isWindows = os.platform() === 'win32'
14+
15+
// process path
16+
const processPath = process.cwd()
17+
18+
// go-libp2p defaults
19+
const goDaemon = {
20+
defaultSock: getSockPath('/tmp/p2pd-go.sock'),
21+
bin: path.join('go-libp2p-dep', 'go-libp2p', isWindows ? 'p2pd.exe' : 'p2pd')
22+
}
23+
24+
// js-libp2p defaults
25+
const jsDaemon = {
26+
defaultSock: getSockPath('/tmp/p2pd-js.sock'),
27+
bin: path.join('libp2p-daemon', 'src', 'cli', 'bin.js')
28+
}
29+
30+
class Daemon {
31+
/**
32+
* @constructor
33+
* @param {String} type daemon implementation type ("go" or "js")
34+
* @param {String} sock unix socket path
35+
*/
36+
constructor (type, sock) {
37+
assert(type === 'go' || type === 'js', 'invalid type received. Should be "go" or "js"')
38+
39+
this._client = undefined
40+
this._type = type
41+
this._binPath = this._getBinPath(type)
42+
this._sock = sock && getSockPath(sock)
43+
44+
if (!this._sock) {
45+
this._sock = type === 'go' ? goDaemon.defaultSock : jsDaemon.defaultSock
46+
}
47+
}
48+
49+
/**
50+
* Get binary path according to implementation and OS
51+
* @param {String} type daemon implementation type ("go" or "js")
52+
* @returns {String}
53+
*/
54+
_getBinPath (type) {
55+
const depPath = type === 'go' ? goDaemon.bin : jsDaemon.bin
56+
let npmPath = path.join(processPath, '../', depPath)
57+
58+
if (fs.existsSync(npmPath)) {
59+
return npmPath
60+
}
61+
62+
npmPath = path.join(processPath, 'node_modules', depPath)
63+
64+
if (fs.existsSync(npmPath)) {
65+
return npmPath
66+
}
67+
68+
throw new Error('Cannot find the libp2p executable')
69+
}
70+
71+
/**
72+
* @async
73+
* Starts a daemon and a client associated with it.
74+
* @returns {void}
75+
*/
76+
async start () {
77+
if (this._client) {
78+
throw new Error('Daemon has already started')
79+
}
80+
81+
// start daemon
82+
await this._startDaemon()
83+
84+
// start client
85+
this._client = new Client(this._sock)
86+
87+
await this._client.attach()
88+
}
89+
90+
/**
91+
* Starts the specifiec daemon and wait for its start.
92+
* @returns {Promise}
93+
*/
94+
_startDaemon () {
95+
return new Promise((resolve, reject) => {
96+
const options = this._type === 'go' ? ['-listen', `/unix${this._sock}`] : ['--sock', this._sock]
97+
const daemon = execa(this._binPath, options)
98+
99+
daemon.stdout.once('data', () => {
100+
return resolve()
101+
})
102+
daemon.stderr.once('data', (data) => {
103+
return reject(data.toString())
104+
})
105+
})
106+
}
107+
108+
/**
109+
* @async
110+
* Stops the daemon client and cleans the unix socket.
111+
* @returns {void}
112+
*/
113+
async stop () {
114+
await this._client && this._client.close()
115+
await this._cleanUnixSocket()
116+
}
117+
118+
/**
119+
* Cleans the unix socket.
120+
* @returns {Promise}
121+
*/
122+
_cleanUnixSocket () {
123+
return new Promise((resolve, reject) => {
124+
rimraf(this._sock, (err) => {
125+
if (err) {
126+
return reject(err)
127+
}
128+
resolve()
129+
})
130+
})
131+
}
132+
133+
/**
134+
* libp2p client instance
135+
* @type {Client}
136+
*/
137+
get client () {
138+
return this._client
139+
}
140+
}
141+
142+
exports = module.exports = Daemon

src/utils.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
'use strict'
2+
3+
const os = require('os')
4+
const path = require('path')
5+
const isWindows = Boolean(os.type().match(/windows/gi))
6+
7+
exports.getSockPath = (sockPath) => isWindows
8+
? path.join('\\\\?\\pipe', sockPath)
9+
: path.resolve(os.tmpdir(), sockPath)

test/connect/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Connect
2+
3+
In this set of tests, we intend to guarantee that nodes implemented in a specific language are able to connect with nodes implemented in a different language.

test/connect/go2go.js

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/* eslint-env mocha */
2+
'use strict'
3+
4+
const chai = require('chai')
5+
chai.use(require('dirty-chai'))
6+
chai.use(require('chai-checkmark'))
7+
const expect = chai.expect
8+
9+
const Daemon = require('../../src/daemon')
10+
11+
describe('connect', () => {
12+
let goDaemon1
13+
let goDaemon2
14+
15+
// Start Daemons
16+
before(async function () {
17+
this.timeout(20 * 1000)
18+
19+
goDaemon1 = new Daemon('go')
20+
goDaemon2 = new Daemon('go', '/tmp/p2pd-go2.sock')
21+
22+
await goDaemon1.start()
23+
await goDaemon2.start()
24+
})
25+
26+
// Stop daemons
27+
after(async function () {
28+
await goDaemon1.stop()
29+
await goDaemon2.stop()
30+
})
31+
32+
it('go peer to go peer', async function () {
33+
this.timeout(10 * 1000)
34+
35+
const identify1 = await goDaemon1.client.identify()
36+
37+
const knownPeersBeforeConnect = await goDaemon2.client.listPeers()
38+
expect(knownPeersBeforeConnect).to.have.lengthOf(0)
39+
40+
// connect peers
41+
await goDaemon2.client.connect(identify1.peerId, identify1.addrs)
42+
43+
const knownPeersAfterConnect = await goDaemon2.client.listPeers()
44+
expect(knownPeersAfterConnect).to.have.lengthOf(1)
45+
expect(knownPeersAfterConnect[0].toB58String()).to.equal(identify1.peerId.toB58String())
46+
})
47+
})

0 commit comments

Comments
 (0)