From a09ac4a8076d0f865aa96b0857105e61392e93de Mon Sep 17 00:00:00 2001 From: Vasco Santos Date: Fri, 6 Nov 2020 16:28:12 +0100 Subject: [PATCH] chore: add test setup for node tests and test for auto-relay --- .travis.yml | 7 +++ examples/auto-relay/test.js | 94 ++++++++++++++++++++++++++++++++++++ examples/package.json | 16 +++++++ examples/test-all.js | 33 +++++++++++++ examples/test.js | 95 +++++++++++++++++++++++++++++++++++++ examples/utils.js | 61 ++++++++++++++++++++++++ package.json | 1 + 7 files changed, 307 insertions(+) create mode 100644 examples/auto-relay/test.js create mode 100644 examples/package.json create mode 100644 examples/test-all.js create mode 100644 examples/test.js create mode 100644 examples/utils.js diff --git a/.travis.yml b/.travis.yml index bb21bd4028..55def3faff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,5 +46,12 @@ jobs: - npm install - LIBP2P_JS=${TRAVIS_BUILD_DIR}/src/index.js npx aegir test -t node --bail + - stage: test + name: example - auto-relay + script: + - cd examples + - npm install + - npm run test -- auto-relay + notifications: email: false \ No newline at end of file diff --git a/examples/auto-relay/test.js b/examples/auto-relay/test.js new file mode 100644 index 0000000000..dff3f841d9 --- /dev/null +++ b/examples/auto-relay/test.js @@ -0,0 +1,94 @@ +'use strict' + +const path = require('path') +const execa = require('execa') +const pDefer = require('p-defer') +const uint8ArrayToString = require('uint8arrays/to-string') + +function startProcess (name, args = []) { + return execa('node', [path.join(__dirname, name), ...args], { + cwd: path.resolve(__dirname), + all: true + }) +} + +async function test () { + let output1 = '' + let output2 = '' + let output3 = '' + let relayAddr + let autoRelayAddr + + const proc1Ready = pDefer() + const proc2Ready = pDefer() + + // Step 1 process + process.stdout.write('relay.js\n') + + const proc1 = startProcess('relay.js') + proc1.all.on('data', async (data) => { + process.stdout.write(data) + + output1 += uint8ArrayToString(data) + + if (output1.includes('Listening on:') && output1.includes('/p2p/')) { + relayAddr = output1.trim().split('Listening on:\n')[1].split('\n')[0] + proc1Ready.resolve() + } + }) + + await proc1Ready.promise + process.stdout.write('==================================================================\n') + + // Step 2 process + process.stdout.write('auto-relay.js\n') + + const proc2 = startProcess('auto-relay.js', [relayAddr]) + proc2.all.on('data', async (data) => { + process.stdout.write(data) + + output2 += uint8ArrayToString(data) + + if (output2.includes('Listening on:') && output2.includes('/p2p/')) { + autoRelayAddr = output2.trim().split('Listening on:\n')[1] + proc2Ready.resolve() + } + }) + + await proc2Ready.promise + process.stdout.write('==================================================================\n') + + // Step 3 process + process.stdout.write('other-node.js\n') + + const proc3 = startProcess('other-node.js', [autoRelayAddr]) + proc3.all.on('data', async (data) => { + process.stdout.write(data) + + output3 += uint8ArrayToString(data) + + if (output3.includes('Connected to the auto relay node via')) { + const remoteAddr = output3.trim().split('Connected to the auto relay node via ')[1] + + if (remoteAddr === autoRelayAddr) { + proc3.kill() + proc2.kill() + proc1.kill() + } else { + throw new Error('other-node did not dial through the relay') + } + } + }) + + await Promise.all([ + proc1, + proc2, + proc3 + ]).catch((err) => { + if (err.signal !== 'SIGTERM') { + throw err + } + }) +} + +module.exports = test \ No newline at end of file diff --git a/examples/package.json b/examples/package.json new file mode 100644 index 0000000000..feaf656d1b --- /dev/null +++ b/examples/package.json @@ -0,0 +1,16 @@ +{ + "name": "libp2p-examples", + "version": "1.0.0", + "description": "Examples of how to use libp2p", + "scripts": { + "test": "node ./test.js", + "test:all": "node ./test-all.js" + }, + "license": "MIT", + "dependencies": { + "execa": "^2.1.0", + "fs-extra": "^8.1.0", + "p-defer": "^3.0.0", + "which": "^2.0.1" + } +} diff --git a/examples/test-all.js b/examples/test-all.js new file mode 100644 index 0000000000..3ee99e45fa --- /dev/null +++ b/examples/test-all.js @@ -0,0 +1,33 @@ +'use strict' + +process.on('unhandedRejection', (err) => { + console.error(err) + + process.exit(1) +}) + +const path = require('path') +const fs = require('fs') +const { + waitForOutput +} = require('./utils') + +async function testAll () { + for (const dir of fs.readdirSync(__dirname)) { + if (dir === 'node_modules' || dir === 'tests_output') { + continue + } + + const stats = fs.statSync(path.join(__dirname, dir)) + + if (!stats.isDirectory()) { + continue + } + + await waitForOutput('npm info ok', 'npm', ['test', '--', dir], { + cwd: __dirname + }) + } +} + +testAll() diff --git a/examples/test.js b/examples/test.js new file mode 100644 index 0000000000..3da6eccdb9 --- /dev/null +++ b/examples/test.js @@ -0,0 +1,95 @@ +'use strict' + +process.env.NODE_ENV = 'test' +process.env.CI = true // needed for some "clever" build tools + +const fs = require('fs-extra') +const path = require('path') +const execa = require('execa') +const dir = path.join(__dirname, process.argv[2]) + +testExample(dir) + .then(() => {}, (err) => { + if (err.exitCode) { + process.exit(err.exitCode) + } + + console.error(err) + process.exit(1) + }) + +async function testExample (dir) { + await installDeps(dir) + await build(dir) + await runTest(dir) + // TODO: add browser test setup +} + +async function installDeps (dir) { + if (!fs.existsSync(path.join(dir, 'package.json'))) { + console.info('Nothing to install in', dir) + return + } + + if (fs.existsSync(path.join(dir, 'node_modules'))) { + console.info('Dependencies already installed in', dir) + return + } + + const proc = execa.command('npm install', { + cwd: dir + }) + proc.all.on('data', (data) => { + process.stdout.write(data) + }) + + await proc +} + +async function build (dir) { + const pkgJson = path.join(dir, 'package.json') + + if (!fs.existsSync(pkgJson)) { + console.info('Nothing to build in', dir) + return + } + + const pkg = require(pkgJson) + let build + + if (pkg.scripts.bundle) { + build = 'bundle' + } + + if (pkg.scripts.build) { + build = 'build' + } + + if (!build) { + console.info('No "build" or "bundle" script in', pkgJson) + return + } + + const proc = execa('npm', ['run', build], { + cwd: dir + }) + proc.all.on('data', (data) => { + process.stdout.write(data) + }) + + await proc +} + +async function runTest (dir) { + console.info('Running node tests in', dir) + const testFile = path.join(dir, 'test.js') + + if (!fs.existsSync(testFile)) { + console.info('Nothing to test in', dir) + return + } + + const runTest = require(testFile) + + await runTest() +} \ No newline at end of file diff --git a/examples/utils.js b/examples/utils.js new file mode 100644 index 0000000000..aec6df5418 --- /dev/null +++ b/examples/utils.js @@ -0,0 +1,61 @@ +'use strict' + +const execa = require('execa') +const fs = require('fs-extra') +const which = require('which') + +async function isExecutable (command) { + try { + await fs.access(command, fs.constants.X_OK) + + return true + } catch (err) { + if (err.code === 'ENOENT') { + return isExecutable(await which(command)) + } + + if (err.code === 'EACCES') { + return false + } + + throw err + } +} + +async function waitForOutput (expectedOutput, command, args = [], opts = {}) { + if (!await isExecutable(command)) { + args.unshift(command) + command = 'node' + } + + const proc = execa(command, args, opts) + let output = '' + let time = 120000 + + let timeout = setTimeout(() => { + throw new Error(`Did not see "${expectedOutput}" in output from "${[command].concat(args).join(' ')}" after ${time/1000}s`) + }, time) + + proc.all.on('data', (data) => { + process.stdout.write(data) + + output += data.toString('utf8') + + if (output.includes(expectedOutput)) { + clearTimeout(timeout) + proc.kill() + } + }) + + try { + await proc + } catch (err) { + if (!err.killed) { + throw err + } + } +} + +module.exports = { + waitForOutput +} diff --git a/package.json b/package.json index b1ae4c5ebe..042a9a0664 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "test": "npm run test:node && npm run test:browser", "test:node": "aegir test -t node -f \"./test/**/*.{node,spec}.js\"", "test:browser": "aegir test -t browser", + "test:examples": "cd examples && npm run test:all", "release": "aegir release -t node -t browser", "release-minor": "aegir release --type minor -t node -t browser", "release-major": "aegir release --type major -t node -t browser",