├── infrastructure
├── deploy
│ ├── data
│ │ └── certbot
│ │ │ └── .gitkeep
│ ├── controller.png
│ ├── nginx
│ │ ├── Dockerfile
│ │ ├── run.sh
│ │ └── nginx.conf
│ ├── docker-compose.yaml
│ ├── docker-compose.prod.yaml
│ ├── README.md
│ └── init-letsencrypt.sh
├── playbooks
│ ├── roles
│ │ ├── redeploy
│ │ │ ├── handlers
│ │ │ │ └── main.yaml
│ │ │ ├── tasks
│ │ │ │ └── main.yaml
│ │ │ └── templates
│ │ │ │ └── runner.service.j2
│ │ ├── logging
│ │ │ ├── handlers
│ │ │ │ └── main.yaml
│ │ │ ├── templates
│ │ │ │ └── filebeat.yml.j2
│ │ │ └── tasks
│ │ │ │ └── main.yaml
│ │ ├── common
│ │ │ └── tasks
│ │ │ │ └── main.yaml
│ │ └── security
│ │ │ └── tasks
│ │ │ └── main.yaml
│ ├── controller.yaml
│ ├── README.md
│ └── benchmarks.yaml
├── prod-infrastructure.png
├── grafana
│ ├── duplicate-graph.png
│ ├── select-measurement.png
│ └── README.md
├── inventory
│ ├── inventory.yaml
│ └── group_vars
│ │ ├── controllers.yaml
│ │ └── minions.yaml
├── ci
│ └── dockerfile
└── README.md
├── tests
├── fixtures
│ └── .gitignore
├── browser
│ ├── public
│ │ ├── favicon.ico
│ │ └── index.html
│ ├── src
│ │ ├── components
│ │ │ ├── table.css
│ │ │ ├── localState.js
│ │ │ ├── getId.js
│ │ │ ├── initialize-node.js
│ │ │ ├── table.js
│ │ │ ├── test-row.js
│ │ │ ├── add-local-file.js
│ │ │ └── peer-transfer.js
│ │ ├── index.js
│ │ ├── App.js
│ │ ├── index.css
│ │ └── App.css
│ ├── README.md
│ └── package.json
├── util
│ ├── build-browser-test.sh
│ ├── getCommit.sh
│ ├── create-privateKey.js
│ ├── getBranch.sh
│ ├── get-commit.js
│ └── create-files.js
├── constants
│ └── index.js
├── lib
│ ├── clean.js
│ ├── runner.js
│ ├── output.js
│ ├── node-factory.js
│ ├── fixtures.js
│ └── create-node.js
├── benchmarks.sh
├── getIpfs.sh
├── upload-ipfs.sh
├── test.template
├── init-node.http.js
├── unit
│ ├── output.test.js
│ └── fixtures.test.js
├── config
│ ├── default-config-browser.json
│ ├── default-config.json
│ ├── index.js
│ ├── default-config-go.json
│ ├── private-key.json
│ └── go-configs.json
├── init-node.browser.js
├── local-add.go.js
├── init-node.js
├── local-add.js
├── add-multi-kb.browser.js
├── package.json
├── local-extract.js
├── add-multi-kb.js
├── local-add.browser.js
├── peer-transfer.browser.js
├── local-transfer.js
├── extract-js2.go.js
├── pubsub-message.js
├── extract-go2.js
├── multi-peer-transfer.js
└── schema
│ └── results.js
├── .dockerignore
├── architecture.png
├── runner
├── import-hover.png
├── outfile.js
├── lib
│ ├── schema
│ │ ├── restart.js
│ │ ├── header.js
│ │ ├── benchmark.js
│ │ ├── get.js
│ │ └── add.js
│ └── configBenchmarks.js
├── cli.js
├── retrieve.js
├── local.js
├── package.json
├── ipfs.js
├── compress.js
├── test
│ ├── parse.js
│ ├── compress.js
│ ├── configBenchmarks.js
│ └── queue.js
├── provision.js
├── remote.js
├── persistence.js
├── README.md
├── queue.js
├── index.js
├── config.js
└── runner.js
├── scripts
├── runProdEnv.sh
├── runLocalEnv.sh
├── README.md
└── common.sh
├── Dockerfile-runner
├── .gitignore
├── LICENSE
├── CONTRIBUTING.md
├── .circleci
└── config.yml
├── docker-compose.yml
└── README.md
/infrastructure/deploy/data/certbot/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/fixtures/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | runner/node_modules
2 | test/node
3 | data
--------------------------------------------------------------------------------
/architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimpick/benchmarks/master/architecture.png
--------------------------------------------------------------------------------
/runner/import-hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimpick/benchmarks/master/runner/import-hover.png
--------------------------------------------------------------------------------
/tests/browser/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimpick/benchmarks/master/tests/browser/public/favicon.ico
--------------------------------------------------------------------------------
/tests/browser/src/components/table.css:
--------------------------------------------------------------------------------
1 | .table {
2 | height: 100%;
3 | width: 100%;
4 | min-width: 3000px;
5 | }
6 |
--------------------------------------------------------------------------------
/tests/util/build-browser-test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cd browser
4 | pwd
5 | npm install --loglevel=error
6 | npm run build
--------------------------------------------------------------------------------
/infrastructure/deploy/controller.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimpick/benchmarks/master/infrastructure/deploy/controller.png
--------------------------------------------------------------------------------
/infrastructure/playbooks/roles/redeploy/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: reload systemctl
2 | systemd:
3 | daemon_reload: yes
--------------------------------------------------------------------------------
/infrastructure/prod-infrastructure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimpick/benchmarks/master/infrastructure/prod-infrastructure.png
--------------------------------------------------------------------------------
/infrastructure/grafana/duplicate-graph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimpick/benchmarks/master/infrastructure/grafana/duplicate-graph.png
--------------------------------------------------------------------------------
/infrastructure/grafana/select-measurement.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimpick/benchmarks/master/infrastructure/grafana/select-measurement.png
--------------------------------------------------------------------------------
/scripts/runProdEnv.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | MODE=prod
4 | SCRIPTPATH=$(dirname "$0")
5 | source $SCRIPTPATH/common.sh
6 | checkParam $1
7 |
8 | docker-compose $FILES $OP
--------------------------------------------------------------------------------
/infrastructure/playbooks/roles/logging/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: reload filebeat
2 | systemd:
3 | state: restarted
4 | daemon_reload: yes
5 | name: filebeat
--------------------------------------------------------------------------------
/infrastructure/inventory/inventory.yaml:
--------------------------------------------------------------------------------
1 | all:
2 | children:
3 | controllers:
4 | hosts:
5 | 63.33.104.238
6 | minions:
7 | hosts:
8 | 147.75.33.155
--------------------------------------------------------------------------------
/infrastructure/deploy/nginx/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx:alpine
2 |
3 | COPY nginx.conf /etc/nginx/conf.d/default.conf
4 | COPY run.sh /usr/local/bin/run
5 |
6 | ENTRYPOINT ["/usr/local/bin/run"]
--------------------------------------------------------------------------------
/runner/outfile.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const config = require('./config')
4 |
5 | const retrieveCommand = () => {
6 |
7 | try {
8 | return JSON.parse(strResult)
9 | } catch (e) {
10 | throw e
11 | }
12 | }
--------------------------------------------------------------------------------
/tests/util/getCommit.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | IPFS_PATH=$1
4 |
5 | cd ${IPFS_PATH}
6 | if [ -d js-ipfs/.git ]
7 | then
8 | cd js-ipfs
9 | git rev-parse HEAD
10 | else
11 | echo "no commit"
12 | fi
13 |
14 |
15 |
--------------------------------------------------------------------------------
/tests/util/create-privateKey.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const PeerId = require('peer-id')
4 |
5 | PeerId.create({ bits: 1024 }, (err, id) => {
6 | if (err) { throw err }
7 | console.log(JSON.stringify(id.toJSON(), null, 2))
8 | })
9 |
--------------------------------------------------------------------------------
/tests/util/getBranch.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | IPFS_PATH=$1
4 |
5 | cd ${IPFS_PATH}
6 | if [ -d js-ipfs/.git ]
7 | then
8 | cd js-ipfs
9 | git branch | grep \* | cut -d ' ' -f2
10 | else
11 | echo "no commit"
12 | fi
13 |
--------------------------------------------------------------------------------
/infrastructure/inventory/group_vars/controllers.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # user account used to ssh the hosts
3 | remote_user: ubuntu
4 | remote_folder: /data/ipfs-benchmarks/
5 | ansible_ssh_private_key_file: "~/.ssh/id_rsa_ipfs"
6 | nodejs_version: "10.x"
7 |
--------------------------------------------------------------------------------
/tests/constants/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | export const smallFile = 'smallfile'
4 | export const largeFile = 'largefile'
5 |
6 | // sub tests name
7 |
8 | export const emptyRepo = 'empty-repo'
9 | export const populatedRepo = 'populated-repo'
10 |
--------------------------------------------------------------------------------
/scripts/runLocalEnv.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | MODE=local
4 | SCRIPTPATH=$(dirname "$0")
5 | source $SCRIPTPATH/common.sh
6 | checkParam $1
7 |
8 |
9 | mkdir -p $SCRIPTPATH/../data
10 | docker-compose -f $SCRIPTPATH/../infrastructure/deploy/docker-compose.yaml $OP
--------------------------------------------------------------------------------
/tests/browser/src/components/localState.js:
--------------------------------------------------------------------------------
1 | const localState = {
2 | id: null,
3 | version: null,
4 | protocol_version: null,
5 | added_file_hash: null,
6 | added_file_contents: null,
7 | time_s: null,
8 | time_ms: null,
9 | ready: ''
10 | }
11 |
12 | export default localState
13 |
--------------------------------------------------------------------------------
/scripts/README.md:
--------------------------------------------------------------------------------
1 | ## Convenience scripts
2 |
3 | These scripts have built in help.
4 |
5 | 1. `sudo ./runLocalEnv.sh up` run InfluxDB and Grafana locally
6 | 2. `sudo ./runProdEnv.sh up` run the above plus the containerized `runner`, an nginx proxy with let's encrypt [certbot](https://github.com/certbot/certbot).
7 |
8 |
--------------------------------------------------------------------------------
/infrastructure/deploy/nginx/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # get Host IP so we can route traffic for the runner to it
4 | hostip=$(ip route show | awk '/default/ {print $3}')
5 | echo "Host ip = $hostip"
6 | # add host to /etc/hosts as "runner" so nginx can send traffic to it.
7 | echo "$hostip runner" >> /etc/hosts
8 | cat /etc/hosts
9 |
10 | exec nginx -g 'daemon off;'
--------------------------------------------------------------------------------
/Dockerfile-runner:
--------------------------------------------------------------------------------
1 | FROM nearform/alpine3-s2i-nodejs:10
2 |
3 | # Create app directory
4 | WORKDIR /opt/app-root/src
5 |
6 | COPY runner runner
7 | USER root
8 | RUN cd runner && npm install
9 | USER 1001
10 | COPY infrastructure/inventory/inventory.yaml infrastructure/inventory/inventory.yaml
11 |
12 | EXPOSE 3000
13 |
14 | WORKDIR runner
15 | CMD [ "npm", "run", "start" ]
--------------------------------------------------------------------------------
/runner/lib/schema/restart.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const restartResponse = {
4 | $id: 'restartResponse',
5 | 200: {
6 | description: 'Succesful response',
7 | type: 'object',
8 | properties: {
9 | id: { type: 'integer' },
10 | restart: { type: 'boolean' }
11 | }
12 | }
13 | }
14 |
15 | module.exports = {
16 | restartResponse
17 | }
18 |
--------------------------------------------------------------------------------
/infrastructure/inventory/group_vars/minions.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # user account used to ssh the hosts
3 | remote_user: ubuntu
4 | # ansible_ssh_private_key_file: "~/.ssh/id_rsa_ipfs"
5 | # non-sudo user to be created for running process
6 | # action_user: grafana
7 | # action_user_group: docker
8 | nodejs_version: "10"
9 | # docker__users: ["ubuntu", "runner"]
10 | go_ipfs_version: v0.4.10
--------------------------------------------------------------------------------
/tests/lib/clean.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const rimraf = require('rimraf')
4 | const { repoPath } = require('../package.json').config
5 |
6 | const peerRepos = () => {
7 | rimraf(repoPath, function () {
8 | console.log(`Removed ${repoPath}`)
9 | })
10 | }
11 |
12 | const all = () => {
13 | peerRepos()
14 | }
15 |
16 | module.exports = {
17 | peerRepos,
18 | all
19 | }
20 |
--------------------------------------------------------------------------------
/tests/browser/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import 'tachyons'
5 | import 'ipfs-css'
6 | import App from './App'
7 | import { HashRouter, Route, Switch } from 'react-router-dom'
8 |
9 | ReactDOM.render( , document.getElementById('root'))
10 |
--------------------------------------------------------------------------------
/runner/lib/schema/header.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const config = require('../../config')
4 |
5 | const headers = {
6 | $id: 'protect',
7 | type: 'object',
8 | properties: {
9 | 'x-ipfs-benchmarks-api-key': {
10 | type: 'string',
11 | const: config.server.apikey
12 | }
13 | },
14 | required: ['x-ipfs-benchmarks-api-key']
15 | }
16 |
17 | module.exports = {
18 | headers
19 | }
20 |
--------------------------------------------------------------------------------
/tests/benchmarks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #! Add 100 1 KB files to local
4 | node add-multi-kb
5 | #! Initialize node without pre-generated key
6 | node init-node
7 | #! Add file to local repo using unixFS engine
8 | node local-add
9 | #! Get file to local repo
10 | node local-extract
11 | #! Transfer file between two local nodes
12 | node local-transfer
13 | #! transfer files from 4 nodes
14 | node multi-peer-transfer
15 |
--------------------------------------------------------------------------------
/tests/browser/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import './App.css'
3 | import 'react-table/react-table.css'
4 | import Table from './components/table'
5 | class App extends Component {
6 | render () {
7 | return
8 |
9 | IPFS Browser Benchmark
10 |
11 |
12 |
13 | }
14 | }
15 | export default App
16 |
--------------------------------------------------------------------------------
/infrastructure/playbooks/roles/redeploy/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Install packages based on package.json.
3 | become: no
4 | npm:
5 | path: "{{ item.path }}"
6 | with_items:
7 | - { path: "{{remote_folder}}/runner" }
8 | - { path: "{{remote_folder}}/tests" }
9 | - name: Ensure Unit file
10 | template:
11 | src: runner.service.j2
12 | dest: /lib/systemd/system/runner.service
13 | mode: 644
14 | notify:
15 | - reload systemctl
--------------------------------------------------------------------------------
/tests/browser/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/tests/browser/src/components/getId.js:
--------------------------------------------------------------------------------
1 |
2 | var util = require('util')
3 | require('util.promisify').shim()
4 | const getId = async (node, delta, state) => {
5 | const id = util.promisify(node.id)
6 | const res = await id()
7 | const results = { ...state }
8 | results.id = res.id
9 | results.version = res.agentVersion
10 | results.protocol_version = res.protocolVersion
11 | results.time_s = delta[0]
12 | results.time_ms = delta[1]
13 | results.ready = 'ready'
14 | return results
15 | }
16 |
17 | export default getId
18 |
--------------------------------------------------------------------------------
/tests/browser/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | React App
9 |
10 |
11 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/runner/cli.js:
--------------------------------------------------------------------------------
1 | 'user strict'
2 |
3 | const argv = require('yargs').argv
4 | const get = require('simple-get')
5 | const config = require('./config')
6 |
7 | const opts = {
8 | url: `http://localhost:${config.server.port}/`,
9 | body: {
10 | commit: argv.commit || '',
11 | clinic: argv.clinic || 'true'
12 | },
13 | json: true,
14 | headers: {
15 | 'x-ipfs-benchmarks-api-key': config.server.apikey
16 | }
17 | }
18 | get.post(opts, function (err, res) {
19 | if (err) throw err
20 | res.pipe(process.stdout) // `res` is a stream
21 | })
22 |
--------------------------------------------------------------------------------
/tests/util/get-commit.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const util = require('util')
4 | const execute = util.promisify(util.promisify(require('child_process').exec))
5 |
6 | const getIpfsCommit = async () => {
7 | const out = await execute(`${__dirname}/getCommit.sh ${__dirname}/../../`)
8 | return out.stdout.replace(/\n$/, '')
9 | }
10 | const getBranchName = async () => {
11 | const out = await execute(`${__dirname}/getBranch.sh ${__dirname}/../../`)
12 | return out.stdout.replace(/\n$/, '')
13 | }
14 | module.exports = {
15 | getIpfsCommit,
16 | getBranchName }
17 |
--------------------------------------------------------------------------------
/infrastructure/ci/dockerfile:
--------------------------------------------------------------------------------
1 | FROM circleci/node:dubnium-browsers
2 |
3 | USER root
4 | RUN apt-get update \
5 | && apt-get -y install --no-install-recommends \
6 | python-all-dev python-pip rsync \
7 | python-yaml python-jinja2 python-httplib2 python-paramiko python-pkg-resources python-keyczar \
8 | && apt-get clean \
9 | && rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/*
10 |
11 | RUN pip install ansible && \
12 | pip install passlib && \
13 | pip install docker-compose
14 |
15 | USER circleci
16 |
17 | RUN ansible-galaxy install nickjj.docker && \
18 | ansible-galaxy install geerlingguy.nodejs \
--------------------------------------------------------------------------------
/tests/browser/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 40vmin;
8 | }
9 |
10 | .App-header {
11 | background-color: #282c34;
12 | min-height: 100vh;
13 | display: flex;
14 | flex-direction: column;
15 | align-items: center;
16 | justify-content: center;
17 | font-size: calc(10px + 2vmin);
18 | color: white;
19 | }
20 |
21 | .App-link {
22 | color: #61dafb;
23 | }
24 |
25 | @keyframes App-logo-spin {
26 | from {
27 | transform: rotate(0deg);
28 | }
29 | to {
30 | transform: rotate(360deg);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/infrastructure/playbooks/roles/logging/templates/filebeat.yml.j2:
--------------------------------------------------------------------------------
1 | ---
2 | filebeat.inputs:
3 | - type: log
4 | enabled: true
5 | paths:
6 | - /var/log/runner.log
7 | - /var/log/runner.error.log
8 | filebeat.config.modules:
9 | path: ${path.config}/modules.d/*.yml
10 | reload.enabled: false
11 | setup.template.settings:
12 | index.number_of_shards: 3
13 | setup.kibana:
14 | output.logstash:
15 | hosts: ["logstash.locotorp.info:5045"]
16 | ssl.certificate_authorities: ["/etc/filebeat/ca.crt"]
17 | processors:
18 | - add_host_metadata: ~
19 | - add_cloud_metadata: ~
20 | - decode_json_fields:
21 | fields: ["message"]
22 | target: ""
--------------------------------------------------------------------------------
/runner/lib/schema/benchmark.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const clinicOperation = {
4 | type: 'array',
5 | items: {
6 | type: 'object',
7 | properties: {
8 | fileSet: { type: 'string' }
9 | }
10 | }
11 | }
12 | const benchmarkResponse = {
13 | $id: 'benchmarkResponse',
14 | 200: {
15 | description: 'Succesful response',
16 | type: 'array',
17 | items: {
18 | type: 'object',
19 | properties: {
20 | name: { type: 'string' },
21 | doctor: clinicOperation,
22 | flame: clinicOperation,
23 | bubbleProf: clinicOperation
24 | }
25 | }
26 | }
27 | }
28 |
29 | module.exports = {
30 | benchmarkResponse
31 | }
32 |
--------------------------------------------------------------------------------
/tests/getIpfs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | IPFS_PATH=$1
4 | COMMIT=$2
5 |
6 | cd ${IPFS_PATH}
7 | if [ ! -d js-ipfs/.git ]
8 | then
9 | echo "> No git repo for js-ipfs, cloning..."
10 | git clone https://github.com/ipfs/js-ipfs.git 2>&1
11 | cd js-ipfs
12 | else
13 | echo "> Git repo for js-ipfs found, updating..."
14 | cd js-ipfs
15 | git checkout master 2>&1
16 | git pull 2>&1
17 | fi
18 |
19 | if [ -z "$COMMIT" ]
20 | then
21 | echo "> using MASTER"
22 | else
23 | echo "> using commit: $COMMIT"
24 | git config --global advice.detachedHead false
25 | git checkout $COMMIT 2>&1
26 | fi
27 | echo "run npm install for js-ipfs"
28 | source ~/.nvm/nvm.sh
29 | npm install --loglevel=error
--------------------------------------------------------------------------------
/tests/util/create-files.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { generateFiles, verifyTestFiles } = require('../lib/fixtures')
4 |
5 | /**
6 | * This utlilty will verify or create files needed for the tests.
7 | * The config is at ../lib/fixtures.file
8 | *
9 | * @async
10 | * @function verifyAndCreateFiles
11 | */
12 | const verifyAndCreateFiles = async () => {
13 | const valid = await verifyTestFiles()
14 | if (!valid) {
15 | console.log('Some files missing. Generating files')
16 | await generateFiles()
17 | } else {
18 | console.log('Files Verified')
19 | }
20 | }
21 | if (require.main === module) {
22 | verifyAndCreateFiles()
23 | }
24 | module.exports = verifyAndCreateFiles
25 |
--------------------------------------------------------------------------------
/infrastructure/playbooks/roles/redeploy/templates/runner.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=IPFS benchmark runner
3 | Requires=network.target
4 | After=network.target
5 | [Service]
6 | ExecStart=/bin/bash -c "IPFS_PASSWORD=$(cat /etc/pwd.txt) /usr/bin/node {{ remote_folder }}/runner/index.js"
7 | User={{ remote_user }}
8 | Restart=always
9 | Environment="STAGE=remote"
10 | Environment="BENCHMARK_USER={{ remote_user }}"
11 | Environment="LOGLEVEL=debug"
12 | Environment="CLINIC=true"
13 | Environment="HOSTNAME=benchmarks.ipfs.team"
14 | Environment="DATADIR=/data/tmp"
15 | EnvironmentFile=-/etc/environment
16 | StandardOutput=file:/var/log/runner.log
17 | StandardError=file:/var/log/runner.error.log
18 | [Install]
19 | WantedBy=multi-user.target
--------------------------------------------------------------------------------
/infrastructure/playbooks/roles/logging/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Add the filebeat apt key
3 | shell: |
4 | wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
5 | - name: Add filebeat apt repository
6 | become: yes
7 | apt_repository:
8 | repo: deb https://artifacts.elastic.co/packages/6.x/apt stable main
9 | state: present
10 | - name: Update repositories cache and install filebeat
11 | become: yes
12 | apt:
13 | name:
14 | - filebeat
15 | update_cache: true
16 | state: present
17 | - name: Ensure filebeat config file
18 | become: yes
19 | template:
20 | src: filebeat.yml.j2
21 | dest: /etc/filebeat/filebeat.yml
22 | mode: "u=rwx,g=r,o=r"
23 | notify:
24 | - reload filebeat
--------------------------------------------------------------------------------
/tests/browser/README.md:
--------------------------------------------------------------------------------
1 | ## Browser Benchmarks
2 |
3 | This is a single page app that containes benchamrks for running IPFS in the browser.
4 | The idea is that each test will have a button to active the test and give feedback on the time it takes.
5 |
6 | This app is integrated with the benchmark running where the results are feed to the IPFS dashbaord.
7 |
8 |
9 | ### `npm run build`
10 |
11 | Builds the app for production to the `build` folder.
12 | It correctly bundles React in production mode and optimizes the build for the best performance.
13 |
14 | The build is minified and the filenames include the hashes.
15 | Your app is ready to be deployed!
16 |
17 | The build/index.html is avaiable via web browser and does not need a web server to view the test table.
18 |
19 |
20 |
--------------------------------------------------------------------------------
/scripts/common.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Usage info
4 | usage() {
5 | FILESTRING="/infrastructure/deploy/docker-compose.yaml"
6 | if [[ $0 == *"runProdEnv"* ]];then
7 | FILESTRING+=" plus overrides from /infrastructure/deploy/docker-compose.prod.yaml"
8 | fi
9 | cat << EOF
10 |
11 | Usage: ${0##*/} [COMMAND]
12 |
13 | Run a docker-compose COMMAND for local puposes using the compose file
14 | $FILESTRING
15 | COMMAND any of the supported COMMANDs from https://docs.docker.com/compose/reference/overview/
16 |
17 | EOF
18 | }
19 |
20 | checkParam () {
21 | if [ -z "$1" ]; then
22 | usage
23 | exit 1
24 | else
25 | OP=$1
26 | fi
27 | }
28 |
29 | FILES="-f $SCRIPTPATH/../infrastructure/deploy/docker-compose.yaml -f $SCRIPTPATH/../infrastructure/deploy/docker-compose.prod.yaml"
30 |
--------------------------------------------------------------------------------
/tests/upload-ipfs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | OUTPATH=$1
4 | TESTNAME=$2
5 |
6 | # Usage info
7 | usage() {
8 | cat << EOF
9 |
10 | Usage: ${0##*/}
11 |
12 | Upload a directory to ipfs and store the SHA in a json file at /.json
13 |
14 | outputPath something like '/tmp/out'
15 | TestName something like 'localAdd'
16 |
17 | EOF
18 | }
19 |
20 | if [ -z "$TESTNAME" ] || [ -z "$OUTPATH" ]
21 | then
22 | usage
23 | exit 1
24 | fi
25 |
26 | # doesn't work yet
27 | # ipfs-cluster-ctl --host /dnsaddr/cluster.ipfs.io --basic-auth $IPFSUSER:$IPFSPWD add /tmp/out/$TESTNAME
28 | SHA="c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2"
29 | mkdir -p $OUTPATH
30 | # echo some sha for now
31 | echo "Writing IPFS sha to $OUTPATH/$TESTNAME.json"
32 | echo "{ \"sha\": \"$SHA\" }" > $OUTPATH/$TESTNAME.json
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | tests/node_modules
2 | tests/browser/node_modules
3 | runner/node_modules
4 | runner/test/db
5 | local/data
6 | tests/dirHash.txt
7 | tests/out
8 | tests/data
9 | tests/package-lock.json
10 | tests/browser/package-lock.json
11 | js-ipfs
12 | infrastructure/inventory/inventory.local.yaml
13 | data
14 | infrastructure/playbooks/*.retry
15 | *clinic*
16 | tests/node_trace.*.log
17 |
18 | # browser dependencies
19 | tests/browser/node_modules
20 | tests/browser/.pnp
21 | tests/browser/.pnp.js
22 |
23 | # testing
24 | tests/browser/coverage
25 |
26 | # production
27 | tests/browser/build
28 |
29 | # misc
30 | tests/browser/.DS_Store
31 | tests/browser/.env.local
32 | tests/browser/.env.development.local
33 | tests/browser/.env.test.local
34 | tests/browser/.env.production.local
35 |
36 | tests/browser/npm-debug.log*
37 | tests/browser/yarn-debug.log*
38 | tests/browser/yarn-error.log*
39 |
--------------------------------------------------------------------------------
/tests/test.template:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const fs = require('fs')
4 | const { build } = require('./schema/results')
5 | const { file } = require('./lib/fixtures')
6 | const run = require('./lib/runner')
7 |
8 | async function ****TEST NAME***** (node, name, warmup, fileSet, version) {
9 |
10 |
11 | *** SETUP ****
12 | const filePath = await file(fileSet)
13 | const start = process.hrtime()
14 |
15 | **** ADD ACTION to be tested ****
16 |
17 | const end = process.hrtime(start)
18 |
19 | // Pass in test output to build and return
20 |
21 | return build({
22 | name: name,
23 | warmup: warmup,
24 | file: filePath,
25 | meta: { version: version },
26 | description: 'Get file to local repo',
27 | file_set: fileSet,
28 | duration: {
29 | s: end[0],
30 | ms: end[1] / 1000000
31 | }
32 | subtest: subtest,
33 | })
34 | }
35 |
36 | run(****TEST NAME***** )
37 |
--------------------------------------------------------------------------------
/runner/retrieve.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Rsync = require('rsync')
4 | const fs = require('fs')
5 |
6 | module.exports = (config, run, targetDir) => {
7 | const targetPath = `${targetDir}/${run.benchmarkName}/${run.operation}/${run.fileSet}`
8 | fs.mkdirSync(targetPath, { recursive: true })
9 | var rsync = new Rsync()
10 | .flags('avz')
11 | .shell(`ssh -i ${config.benchmarks.key}`)
12 | .source(`${config.benchmarks.user}@${config.benchmarks.host}:${config.outFolder}/${run.benchmarkName}/`)
13 | .destination(targetPath)
14 | config.log.info(`Retrieving the clinic files with [${rsync.command()}]`)
15 | return new Promise((resolve, reject) => {
16 | rsync.execute(function (error, code, cmd) {
17 | if (error) {
18 | reject(error)
19 | } else {
20 | config.log.info(code)
21 | config.log.info(cmd)
22 | resolve(targetPath)
23 | }
24 | })
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/infrastructure/deploy/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | version: "3.2"
2 | services:
3 | influxdb:
4 | image: influxdb:1.7-alpine
5 | volumes:
6 | - type: volume
7 | source: grafana
8 | target: /var/lib/influxdb
9 | volume:
10 | nocopy: true
11 | ports:
12 | - "8086:8086"
13 | environment:
14 | INFLUXDB_DB: benchmarks
15 | grafana:
16 | image: grafana/grafana:latest
17 | ports:
18 | - "3000:3000"
19 | volumes:
20 | - type: volume
21 | source: grafana
22 | target: /var/lib/grafana
23 | volume:
24 | nocopy: true
25 | depends_on:
26 | - influxdb
27 | links:
28 | - influxdb
29 | environment:
30 | GF_SERVER_ROOT_URL: http://localhost
31 | GF_AUTH_ANONYMOUS_ENABLED: 'true'
32 | GF_AUTH_ANONYMOUS_ORG_ROLE: Viewer
33 | rendezvous:
34 | image: libp2p/websocket-star-rendezvous:release
35 | ports:
36 | - "9090:9090"
37 | environment:
38 | DISABLE_METRICS: 1
39 | volumes:
40 | influx:
41 | grafana:
--------------------------------------------------------------------------------
/tests/init-node.http.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { build } = require('./schema/results')
4 | const run = require('./lib/runner')
5 | const NodeFactory = require('./lib/node-factory')
6 |
7 | async function initializeNodeHttp (node, name, warmup, fileSet, version) {
8 | const start = process.hrtime()
9 | const nodeFactory = new NodeFactory()
10 | await nodeFactory.add('http', {
11 | 'Addresses': {
12 | 'API': '/ip4/127.0.0.1/tcp/6012',
13 | 'Gateway': '/ip4/127.0.0.1/tcp/9191',
14 | 'Swarm': [
15 | '/ip4/0.0.0.0/tcp/7012',
16 | '/ip4/127.0.0.1/tcp/3022/ws'
17 | ]
18 | },
19 | 'Bootstrap': []
20 | }, { 'empty-repo': true })
21 | const end = process.hrtime(start)
22 | await nodeFactory.stop('http')
23 | return build({
24 | name: name,
25 | wamrup: warmup,
26 | file: '',
27 | meta: { version: version },
28 | description: 'Initialize node without pre-generated key',
29 | file_set: '',
30 | duration: { s: end[0],
31 | ms: end[1] / 1000000 }
32 | })
33 | }
34 |
35 | run(initializeNodeHttp)
36 |
--------------------------------------------------------------------------------
/tests/unit/output.test.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = require('tap')
4 | const { createFilename, write } = require('../lib/output')
5 | const { resultsDTO, build, validate } = require('../schema/results')
6 | const test = t.test
7 |
8 | test('validate - results ', t => {
9 | t.plan(2)
10 | const e = validate(resultsDTO)
11 | t.equal(e, true)
12 | t.pass()
13 | })
14 |
15 | test('validate - invalid results ', t => {
16 | t.plan(2)
17 | const valid = validate({ name: 0 })
18 | t.equal(valid, false)
19 | t.pass()
20 | })
21 |
22 | test('validate - create filename ', t => {
23 | t.plan(1)
24 | createFilename('out', resultsDTO)
25 | t.pass()
26 | })
27 |
28 | test('validate - create error dir filename ', t => {
29 | t.plan(1)
30 | createFilename('out/error', { invalidefile: 'yes' })
31 | t.pass()
32 | })
33 |
34 | test('validate - write flename ', t => {
35 | t.plan(1)
36 | write(resultsDTO)
37 | t.pass()
38 | })
39 |
40 | test('validate - write file to error directory ', t => {
41 | t.plan(1)
42 | write(build({ name: 0 }))
43 | t.pass()
44 | })
45 |
--------------------------------------------------------------------------------
/tests/unit/fixtures.test.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = require('tap')
4 | const { file, isDirectory } = require('../lib/fixtures')
5 | const test = t.test
6 |
7 | test('Files - file exists ', async t => {
8 | t.plan(2)
9 | const filepath = await file('one4mbfile')
10 | t.equal(filepath.includes('one4mbfile.txt'), true)
11 | t.pass()
12 | })
13 | test('Files - file does not exist ', async t => {
14 | t.plan(2)
15 | const filepath = await file('NoOneKBFile')
16 | t.equal(typeof filepath === 'undefined', true)
17 | t.pass()
18 | })
19 | test('Is not a Directory ', async t => {
20 | t.plan(2)
21 | const results = await isDirectory('OneKBFile')
22 |
23 | t.assert(!results)
24 | t.pass()
25 | })
26 |
27 | test('Is a Directory ', async t => {
28 | t.plan(2)
29 | const results = await isDirectory('hundred1kbfile')
30 |
31 | t.assert(results)
32 | t.pass()
33 | })
34 | test('File set ', async t => {
35 | t.plan(2)
36 | const results = await file('hundred1kbfile')
37 | console.log(results.length)
38 | t.assert(results.length === 100)
39 | t.pass()
40 | })
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Protocol Labs, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/runner/lib/schema/get.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const getResponse = {
4 | $id: 'getResponse',
5 | 200: {
6 | description: 'Succesful response',
7 | type: 'array',
8 | items: {
9 | type: 'object',
10 | properties: {
11 | jobId: { type: 'integer' },
12 | work: {
13 | type: 'object',
14 | properties: {
15 | commit: { type: 'string' },
16 | clinic: {
17 | type: 'object',
18 | properties: {
19 | enabled: { type: 'boolean' }
20 | }
21 | },
22 | benchmarks: {
23 | type: 'object',
24 | properties: {
25 | tests: {
26 | type: 'array',
27 | items: { type: 'string' }
28 | }
29 | }
30 | },
31 | remote: { type: 'boolean' },
32 | nightly: { type: 'boolean' }
33 | }
34 | },
35 | status: { type: 'string' },
36 | queued: { type: 'string' },
37 | started: { type: 'string' }
38 | }
39 | }
40 | }
41 | }
42 |
43 | module.exports = {
44 | getResponse
45 | }
46 |
--------------------------------------------------------------------------------
/tests/browser/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "browser",
3 | "version": "0.1.0",
4 | "private": true,
5 | "homepage": "./",
6 | "config": {
7 | "repoPath": "./data/ipfs/"
8 | },
9 | "dependencies": {
10 | "browser-process-hrtime": "^1.0.0",
11 | "filereader-stream": "^2.0.0",
12 | "ipfs": "file:../../js-ipfs",
13 | "ipfs-css": "^0.12.0",
14 | "libp2p": "^0.24.4",
15 | "libp2p-websockets": "^0.12.2",
16 | "react": "^16.6.3",
17 | "react-dom": "^16.6.3",
18 | "react-router-dom": "^4.3.1",
19 | "react-scripts": "2.1.1",
20 | "react-table": "^6.8.6",
21 | "stream-iterators-utils": "^0.1.0",
22 | "tachyons": "^4.11.1",
23 | "util": "^0.11.1",
24 | "util.promisify": "^1.0.0",
25 | "webcrypto-shim": "^0.1.4"
26 | },
27 | "scripts": {
28 | "start": "REACT_APP_REMOTE=true react-scripts start",
29 | "build": "REACT_APP_REMOTE=true react-scripts build",
30 | "startDev": "react-scripts start",
31 | "buildDev": "react-scripts build",
32 | "test": "react-scripts test",
33 | "eject": "react-scripts eject"
34 | },
35 | "browserslist": [
36 | ">0.2%",
37 | "not dead",
38 | "not ie <= 11",
39 | "not op_mini all"
40 | ]
41 | }
42 |
--------------------------------------------------------------------------------
/infrastructure/playbooks/roles/common/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: create remote_folder
3 | become: yes
4 | file:
5 | path: "{{ remote_folder }}"
6 | state: directory
7 | mode: 0755
8 | owner: ubuntu
9 | group: docker
10 | recurse: yes
11 | - name: create influxdb and grafana data dirs
12 | become: yes
13 | file:
14 | path: "{{ item.path }}"
15 | owner: "{{ item.uid | default('ubuntu') }}"
16 | group: "{{ item.guid | default('docker') }}"
17 | state: directory
18 | recurse: yes
19 | mode: 0755
20 | with_items:
21 | - { path: '/data/influxdb' }
22 | - { path: '/data/grafana', uid: 472, guid: docker }
23 | - { path: '/data/ipfs-db' }
24 | - { path: '/data/tmp' }
25 | - name: install ansible
26 | pip:
27 | name: ansible
28 | - name: install ansible modules
29 | become: no
30 | shell: ansible-galaxy install geerlingguy.nodejs
31 | - name: install ipfs-cluster-ctl
32 | shell: |
33 | wget https://dist.ipfs.io/ipfs-cluster-ctl/v0.7.0/ipfs-cluster-ctl_v0.7.0_linux-amd64.tar.gz
34 | tar zxvf ipfs-cluster-ctl_v0.7.0_linux-amd64.tar.gz
35 | cp ipfs-cluster-ctl/ipfs-cluster-ctl /usr/local/bin
36 | chmod +x /usr/local/bin/ipfs-cluster-ctl
37 | args:
38 | creates: /usr/local/bin/ipfs-cluster-ctl
--------------------------------------------------------------------------------
/tests/browser/src/components/initialize-node.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import IPFS from 'ipfs'
3 | import hrtime from 'browser-process-hrtime'
4 | import uuidv1 from 'uuid/v1'
5 | import 'react-table/react-table.css'
6 | import { once } from 'stream-iterators-utils'
7 | import getId from './getId'
8 | import localState from './localState'
9 | import TestRow from './test-row'
10 | class InitializeNode extends React.Component {
11 | constructor (props) {
12 | super(props)
13 | this.state = localState
14 | }
15 |
16 | async test (e) {
17 | // Create the IPFS node instance
18 | const start = hrtime()
19 | const node = new IPFS({ repo: String(uuidv1()) })
20 | node.on('ready', () => {
21 | })
22 | await once(node, 'ready')
23 | const delta = hrtime(start)
24 | const results = await getId(node, delta, this.state)
25 | this.setState(results)
26 | }
27 | render () {
28 | const name = 'initializeNode'
29 | const description = 'Initialize an IPFS node'
30 | return (
31 |
38 | )
39 | }
40 | }
41 | export default InitializeNode
42 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## repository organization
2 | ```
3 | ├── docs
4 | ├── infrastructure
5 | │ ├── grafana
6 | │ ├── inventory
7 | │ ├── local
8 | │ └── playbooks
9 | ├── runner
10 | ├── scripts
11 | └── tests
12 | ```
13 |
14 | ### docs
15 | Documentation and images for usage of this repository
16 |
17 | ### infrastructure
18 | * _grafana_: Any [Grafana](https://grafana.com/) configurations for dashboards and such.
19 | * _inventory_: Defines the hosts this project is targeting for production
20 | * _local_: Any infrastructure parts needed to run this in a local system. Requires `docker-compose` to be installed. It will run containers for [Grafana](https://grafana.com/) and [InfluxDB](https://www.influxdata.com/time-series-platform/influxdb/). See below for more details.
21 | * _playbooks_: [Ansible](https://www.ansible.com/) playbooks run by the runner to provision the target benchmark system.
22 |
23 | ### runner
24 | Houses the `runner` code and configuration. `npm install` should be run in this folder.
25 | Use `npm run tests` to execute tests (TBD)
26 |
27 | ### scripts
28 | Various convenience scripts to make running things a bit easier
29 |
30 | ### tests
31 | Houses the code for the benchmarks. `npm install` should be run in this folder.
32 | Use `npm run tests` to execute tests
--------------------------------------------------------------------------------
/tests/browser/src/components/table.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import AddLocalFile from './add-local-file'
3 | import InitializeNode from './initialize-node'
4 | import PeerTransfer from './peer-transfer'
5 | import './table.css'
6 | export default class Table extends React.Component {
7 | render () {
8 | return (
9 |
21 | )
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/runner/local.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { spawn } = require('child_process')
4 |
5 | const config = require('./config')
6 |
7 | const run = (shell, name) => {
8 | config.log.info(`Running [${shell}] locally`)
9 | let args = shell.split(' ')
10 | let cmd = args[0]
11 | args.shift()
12 |
13 | return new Promise((resolve, reject) => {
14 | if (!shell) return reject(Error('shell command required'))
15 | let cmdInstance = spawn(cmd, args)
16 | let stdOut = ''
17 | let stdErr = ''
18 | const commandLogger = config.log.child({command: cmd})
19 | cmdInstance.stdout.on('data', (data) => {
20 | commandLogger.debug(data.toString())
21 | stdOut += data
22 | })
23 | cmdInstance.stderr.on('data', (data) => {
24 | commandLogger.error(data.toString())
25 | stdErr += data
26 | })
27 | cmdInstance.on('close', (code) => {
28 | commandLogger.debug(`-- main command end ${code} --`)
29 | if (code === 0) {
30 | resolve(stdOut)
31 | } else {
32 | commandLogger.error('error', code)
33 | commandLogger.error(stdErr)
34 | reject(new Error(stdErr))
35 | }
36 | })
37 | cmdInstance.on('error', (err) => {
38 | commandLogger.error(err, 'Local command error')
39 | })
40 | })
41 | }
42 |
43 | module.exports = {
44 | run: run
45 | }
46 |
--------------------------------------------------------------------------------
/tests/browser/src/components/test-row.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export default class TestRow extends React.Component {
4 | render () {
5 | return (
6 |
7 | {this.props.type === 'button' ?
8 | : this.props.test(e)} />}
9 |
{this.props.description}
10 |
ID:{this.props.results.id}
11 |
IPFS version: {this.props.results.version}
12 |
IPFS protocol version:{this.props.results.protocol_version}
13 |
14 |
secs:{this.props.results.time_s}
15 |
milli:{this.props.results.time_ms}
16 |
)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/runner/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "runner",
3 | "version": "0.1.0",
4 | "description": "runner for benchmark tests",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "tap test/*.js",
8 | "lint": "standard --verbose",
9 | "start": "node index.js"
10 | },
11 | "contributors": [
12 | "Matteo Collina ",
13 | "Alex Knol ",
14 | "Ron Litzenberegr "
15 | ],
16 | "license": "MIT",
17 | "dependencies": {
18 | "ajv": "^6.5.5",
19 | "compressing": "^1.4.0",
20 | "fastify": "^1.13.0",
21 | "fastify-swagger": "^1.1.1",
22 | "folder-hash": "^2.1.2",
23 | "influx": "^5.0.7",
24 | "level-jobs": "^2.1.0",
25 | "leveldown": "^4.0.1",
26 | "levelup": "^4.0.0",
27 | "lodash": "^4.17.11",
28 | "make-promises-safe": "^3.0.0",
29 | "memdown": "^3.0.0",
30 | "moment": "^2.22.2",
31 | "nock-exec": "^0.1.0",
32 | "node-schedule": "^1.3.1",
33 | "pino": "^5.8.1",
34 | "pino-multi-stream": "^4.0.1",
35 | "pino-pretty": "^2.2.3",
36 | "rmfr": "^2.0.0",
37 | "rsync": "^0.6.1",
38 | "simple-get": "^3.0.3",
39 | "ssh-exec-plus": "^2.0.1",
40 | "yaml": "^1.0.2",
41 | "yargs": "^12.0.5"
42 | },
43 | "devDependencies": {
44 | "standard": "^11.0.0",
45 | "tap": "^12.1.1"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/runner/ipfs.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const _ = require('lodash')
4 | const config = require('./config')
5 | const local = require('./local')
6 | const fs = require('fs')
7 | const util = require('util')
8 | const fsStat = util.promisify(fs.stat)
9 |
10 | const store = async (localpath) => {
11 | // return new Promise(async (resolve, reject) => {
12 | if (config.ipfs.network.password) {
13 | try {
14 | await fsStat(localpath)
15 | const shellCommand = `ipfs-cluster-ctl --host ${config.ipfs.network.address} --enc json --basic-auth ${config.ipfs.network.user}:${config.ipfs.network.password} add -r ${localpath}`
16 | config.log.debug(shellCommand)
17 | return await local.run(shellCommand)
18 | } catch (e) {
19 | throw e
20 | }
21 | } else {
22 | throw Error('Env var IPFS_PASSWORD not set! Upload failed')
23 | }
24 | // })
25 | }
26 |
27 | const parse = (outString, name) => {
28 | config.log.info(`Return sha for: ${name}`)
29 | name = String(name)
30 | let retVal = ''
31 | var parts = outString.match(/({\n.*\n.*\n.*\n})/g)
32 | config.log.debug(parts)
33 | let almostJson = parts.join(',')
34 | config.log.debug(almostJson)
35 | let arrOut = JSON.parse(`[${almostJson}]`)
36 | config.log.debug(arrOut)
37 | retVal = _.find(arrOut, { name: name }).cid
38 | return retVal
39 | }
40 |
41 | module.exports = {
42 | store,
43 | parse
44 | }
45 |
--------------------------------------------------------------------------------
/runner/compress.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const fs = require('fs')
4 | const util = require('util')
5 | const rmfr = require('rmfr')
6 | const stat = util.promisify(fs.stat)
7 | const readDir = util.promisify(fs.readdir)
8 | const compressing = require('compressing')
9 | const config = require('./config')
10 |
11 | const _tgzDir = async (source, target) => {
12 | if (source && target) {
13 | config.log.info(`Compressing [${source}] to [${target}]`)
14 | await compressing.tgz.compressDir(source, target)
15 | return { result: 'ok' }
16 | } else {
17 | config.log.error(`compress.tgz - Source [${source}] and Target [${target}] are required`)
18 | }
19 | }
20 |
21 | const clinicFiles = async (path) => {
22 | try {
23 | let contents = await readDir(path)
24 | // find the dir
25 | let clinicDir
26 | for (let node of contents) {
27 | let stats = await stat(`${path}/${node}`)
28 | if (stats.isDirectory()) {
29 | clinicDir = node
30 | break
31 | }
32 | }
33 | if (clinicDir) {
34 | await _tgzDir(`${path}/${clinicDir}`, `${path}/${clinicDir}.tar.gz`)
35 | await rmfr(`${path}/${clinicDir}`)
36 | } else {
37 | config.log.error(`No clinic directory found in ${path}`)
38 | }
39 | } catch (e) {
40 | config.log.error(e)
41 | throw e
42 | }
43 | }
44 |
45 | module.exports = {
46 | _tgzDir,
47 | clinicFiles
48 | }
49 |
--------------------------------------------------------------------------------
/infrastructure/playbooks/roles/security/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Allow SSH in UFW
3 | ufw:
4 | rule: allow
5 | port: ssh
6 | proto: tcp
7 | comment: Allow ssh access
8 |
9 | - name: limit ssh brute force
10 | ufw:
11 | rule: limit
12 | port: ssh
13 | proto: tcp
14 | comment: Limit ssh access
15 |
16 | - name: Allow access to http port 80 and include a comment
17 | ufw:
18 | rule: allow
19 | proto: tcp
20 | port: http
21 | comment: Allow http access
22 |
23 | - name: Allow access to https port 443 and include a comment
24 | ufw:
25 | rule: allow
26 | proto: tcp
27 | port: https
28 | comment: Allow https access
29 |
30 | - name: Allow access to https port 9090 and include a comment
31 | ufw:
32 | rule: allow
33 | proto: tcp
34 | port: '9090'
35 | src: '147.75.33.155'
36 | comment: Allow rendezvous server access from benchmark machine
37 |
38 | - name: Create a network with options
39 | docker_network:
40 | name: my-bridge
41 | driver_options:
42 | com.docker.network.bridge.name: my-bridge
43 |
44 | - name: Allow access to http port 9000 on the host include a comment
45 | ufw:
46 | rule: allow
47 | proto: tcp
48 | port: '9000'
49 | direction: in
50 | interface: my-bridge
51 | comment: Allow https access
52 |
53 | - name: Set firewall default policy
54 | ufw:
55 | state: enabled
56 | policy: reject
57 | become: yes
--------------------------------------------------------------------------------
/infrastructure/playbooks/controller.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: controllers
3 | remote_user: "{{remote_user}}"
4 | become_method: sudo
5 | serial: 1
6 | gather_facts: False
7 | pre_tasks:
8 | - name: Install python for Ansible
9 | raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal)
10 | register: test
11 | become: yes
12 | changed_when: test.stdout
13 | - setup:
14 | tasks:
15 | - import_role:
16 | name: logging
17 | become: yes
18 | tags: ["prepare","logging"]
19 | - import_role:
20 | name: security
21 | become: yes
22 | tags: ["prepare","security"]
23 | - import_role:
24 | name: "nickjj.docker"
25 | tags: ["prepare","docker"]
26 | become: yes
27 | - import_role:
28 | name: geerlingguy.nodejs
29 | become: yes
30 | tags: ["prepare","node"]
31 | - import_role:
32 | name: common
33 | become: yes
34 | tags: ["prepare","common"]
35 | - name: copy code
36 | become: no
37 | synchronize:
38 | src: ../../../
39 | dest: "{{ remote_folder }}"
40 | checksum: yes
41 | rsync_opts:
42 | - "--exclude=runner/node_modules"
43 | - "--exclude=tests/node_modules"
44 | - "--exclude=tests/browser/node_modules"
45 | - "--exclude=tests/package-lock.json"
46 | - "--exclude=tests/fixtures/*"
47 | - import_role:
48 | name: redeploy
49 | become: yes
50 | tags: ["redeploy"]
51 |
--------------------------------------------------------------------------------
/tests/config/default-config-browser.json:
--------------------------------------------------------------------------------
1 | {
2 | "Identity": {
3 | "PeerID": "",
4 | "PrivKey": ""
5 | },
6 | "Datastore": {
7 | "Type": "",
8 | "Path": "",
9 | "StorageMax": "",
10 | "StorageGCWatermark": 0,
11 | "GCPeriod": "",
12 | "Params": null,
13 | "NoSync": false
14 | },
15 | "Addresses": {
16 | "Swarm": [
17 | "/ip4/127.0.0.1/tcp/0"
18 | ],
19 | "API": "/ip4/127.0.0.1/tcp/0",
20 | "Gateway": "/ip4/127.0.0.1/tcp/0"
21 | },
22 | "Mounts": {
23 | "IPFS": "/ipfs",
24 | "IPNS": "/ipns",
25 | "FuseAllowOther": false
26 | },
27 | "Version": {
28 | "Current": "jsipfs-dev",
29 | "Check": "error",
30 | "CheckDate": "0001-01-01T00:00:00Z",
31 | "CheckPeriod": "172800000000000",
32 | "AutoUpdate": "minor"
33 | },
34 | "Discovery": {
35 | "MDNS": {
36 | "Enabled": false,
37 | "Interval": 10
38 | },
39 | "webRTCStar": {}
40 | },
41 | "Ipns": {
42 | "RepublishPeriod": "",
43 | "RecordLifetime": "",
44 | "ResolveCacheSize": 128
45 | },
46 | "Bootstrap": [],
47 | "Tour": {
48 | "Last": ""
49 | },
50 | "Gateway": {
51 | "HTTPHeaders": null,
52 | "RootRedirect": "",
53 | "Writable": false
54 | },
55 | "SupernodeRouting": {
56 | "Servers": []
57 | },
58 | "API": {
59 | "HTTPHeaders": null
60 | },
61 | "Swarm": {
62 | "AddrFilters": null
63 | },
64 | "Log": {
65 | "MaxSizeMB": 250,
66 | "MaxBackups": 1,
67 | "MaxAgeDays": 0
68 | }
69 | }
--------------------------------------------------------------------------------
/tests/browser/src/components/add-local-file.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import IPFS from 'ipfs'
3 | import hrtime from 'browser-process-hrtime'
4 | import uuidv1 from 'uuid/v1'
5 | import 'react-table/react-table.css'
6 | import { once } from 'stream-iterators-utils'
7 | import fileReaderStream from 'filereader-stream'
8 | import getId from './getId'
9 | import localState from './localState'
10 | import TestRow from './test-row'
11 | class AddLocalFile extends React.Component {
12 | constructor (props) {
13 | super(props)
14 | this.state = localState
15 | }
16 |
17 | async test (e) {
18 | // Create the IPFS node instance
19 | const node = new IPFS({ repo: String(uuidv1()) })
20 | const fileArray = [...e.target.files]
21 | node.on('ready', () => {})
22 | await once(node, 'ready')
23 | const start = hrtime()
24 | for (let i = 0; i < fileArray.length; i++) {
25 | const readStream = fileReaderStream(fileArray[i])
26 | node.add ? await node.add(readStream) : await node.files.add(readStream)
27 | }
28 | const delta = hrtime(start)
29 | const results = await getId(node, delta, this.state)
30 | this.setState(results)
31 | }
32 | render () {
33 | const name = 'addLocalFile'
34 | const description = 'Add local files'
35 | return (
36 |
42 | )
43 | }
44 | }
45 | export default AddLocalFile
46 |
--------------------------------------------------------------------------------
/tests/init-node.browser.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { build } = require('./schema/results')
4 | const run = require('./lib/runner')
5 |
6 | /**
7 | * Initialize an IPFS peer benchmark test in the browser.
8 | * js0 -> js0 - A local test from one JS IPFS node to the same node
9 | * @async
10 | * @function unixFsAddBrowser
11 | * @param {array} browser - An array of headless browsers that contain IPFS tests.
12 | * @param {string} name - Name of the test used as sending results to the file with same name and data point in dashboard.
13 | * @param {boolean} warmup - Not implemented.
14 | * @param {string} fileSet - Describes file or list of files used for the test.
15 | * @param {string} version - Version of IPFS used in benchmark.
16 | * @return {Promise