Skip to content

Commit

Permalink
Added: benchmark tests
Browse files Browse the repository at this point in the history
Fixed: documentation, c8/coverage config
Changed: test folder structure

Signed-off-by: diva.exchange <61228890+diva-exchange@users.noreply.github.com>
  • Loading branch information
diva-exchange committed Jul 13, 2023
1 parent 9b7217a commit 97e9ffc
Show file tree
Hide file tree
Showing 23 changed files with 200 additions and 64 deletions.
File renamed without changes.
2 changes: 1 addition & 1 deletion .mocharc.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"reporter": "list",
"extensions": ["js"],
"spec": ["lib-test/**/*.spec.js"],
"spec": ["test/compiled-lib/**/*.spec.js"],
"exit": true,
"bail": false
}
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,6 @@ import net from 'net';

NOTE: reply-able datagrams contain the origin of the data. An "origin" is defined as the public key of a node in the I2P network.

NOTE: the example below does not implement any UDP listener and hence the UDP messages are lost. On Linux, you could create a local UDP listener like this: `netcat -ul 20202`. Or take a look at the "streaming" examples above, which do contain a listening socket server.

Send reply-able UDP messages from peer **A** to peer **B** through the I2P network:

```
Expand Down Expand Up @@ -155,8 +153,6 @@ import { createDatagram, toB32 } from '@diva.exchange/i2p-sam';

NOTE: raw datagrams do not contain the "origin" of the data. A typical use case for raw datagrams: broadcasting of data. Raw datagrams are lean.

NOTE: the example below does not implement any UDP listener and hence the UDP messages are lost. On Linux, you could create a local UDP listener like this: `netcat -ul 20202`. Or take a look at the "streaming" examples above, which do contain a listening socket server.

Send raw UDP messages from peer **A** to peer **B** through the I2P network:

```
Expand Down
5 changes: 5 additions & 0 deletions lib/config.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 2 additions & 5 deletions lib/i2p-sam-raw.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 5 additions & 8 deletions lib/i2p-sam-stream.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion lib/i2p-sam.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@diva.exchange/i2p-sam",
"version": "5.0.0",
"version": "5.0.1",
"description": "I2P SAM: peer-to-peer communication between applications over I2P",
"type": "module",
"exports": {
Expand All @@ -26,9 +26,11 @@
"scripts": {
"build": "npm run clean && npm i && tsc && npm run lint",
"clean": "rm -rf lib/*",
"clean-test": "rm -rf lib-test/*",
"clean-test": "rm -rf test/compiled-lib/*",
"clean-benchmark": "rm -rf test/compiled-benchmark/*",
"lint": "prettier -w \"**/*.ts\" && eslint --fix src/ test/ --ext .ts",
"test": "npm run build && npm run clean-test && tsc -p ./test/tsconfig.json && c8 mocha",
"test": "npm run build && npm run clean-test && tsc -p ./test/lib/tsconfig.json && c8 mocha",
"benchmark": "npm run clean-benchmark && tsc -p ./test/benchmark/tsconfig.json && node test/compiled-benchmark/*.js",
"prepublishOnly": "npm run build"
},
"engines": {
Expand Down
143 changes: 143 additions & 0 deletions test/benchmark/i2p-sam-raw.benchmark.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/**
* Copyright 2021-2023 diva.exchange
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author/Maintainer: DIVA.EXCHANGE Association, https://diva.exchange
*/

import { createRaw, I2pSamRaw } from '../../lib/index.js';
import fs from 'fs';
import path from 'path';

const SAM_HOST = process.env.SAM_HOST || '172.19.74.11';
const SAM_PORT_TCP = Number(process.env.SAM_PORT_TCP) || 7656;
const SAM_PORT_UDP = Number(process.env.SAM_PORT_UDP) || 7655;
const SAM_LISTEN_ADDRESS = process.env.SAM_LISTEN_ADDRESS || '0.0.0.0';
const SAM_LISTEN_PORT = Number(process.env.SAM_LISTEN_PORT) || 20222;
const SAM_LISTEN_FORWARD = process.env.SAM_LISTEN_FORWARD || '172.19.74.1';

class TestI2pSamRawBenchmark {
private readonly minutes: number;
private readonly interval: number; // ms
private readonly pathCSV: string;

constructor(minutes: number = 3, interval: number = 100) {
this.minutes = minutes;
this.interval = interval;
const now: Date = new Date();
this.pathCSV = fs.realpathSync(path.dirname(import.meta.url.replace(/^file:\/\//, '')) + '/../data/') + '/';
this.pathCSV += now.toISOString().replace(/[.\-:]/g, '') + '-TestI2pSamRawBenchmark.csv';
}

async run() {
let messageReceived = 0;
const arrayPerformance: Array<number> = [];
let arrayCSV: Array<Array<number>> = [];

let destinationSender = '';
let destinationRecipient = '';

console.log('TestI2pSamRawBenchmark - Creating Sender...');
const i2pSender: I2pSamRaw = (
await createRaw({
session: { options: 'inbound.lengthVariance=2 outbound.lengthVariance=2 shouldBundleReplyInfo=false' },
// session: { options: 'inbound.lengthVariance=-1 outbound.lengthVariance=-1 shouldBundleReplyInfo=false' },
sam: { host: SAM_HOST, portTCP: SAM_PORT_TCP, portUDP: SAM_PORT_UDP },
listen: {
address: SAM_LISTEN_ADDRESS,
port: SAM_LISTEN_PORT,
hostForward: SAM_LISTEN_FORWARD,
},
})
).on('data', (msg: Buffer) => {
messageReceived++;
const n: number = Date.now();
const l: number = n - Number(msg.toString());
arrayPerformance.push(l);
arrayCSV.push([n, l]);
});
destinationSender = i2pSender.getPublicKey();

console.log('TestI2pSamRawBenchmark - Creating Recipient...');
const i2pRecipient: I2pSamRaw = (
await createRaw({
session: { options: 'inbound.lengthVariance=2 outbound.lengthVariance=2 shouldBundleReplyInfo=false' },
// session: { options: 'inbound.lengthVariance=-1 outbound.lengthVariance=-1 shouldBundleReplyInfo=false' },
sam: { host: SAM_HOST, portTCP: SAM_PORT_TCP, portUDP: SAM_PORT_UDP },
listen: {
address: SAM_LISTEN_ADDRESS,
port: SAM_LISTEN_PORT + 1,
hostForward: SAM_LISTEN_FORWARD,
},
})
).on('data', (msg: Buffer) => {
messageReceived++;
const n: number = Date.now();
const l: number = n - Number(msg.toString());
arrayPerformance.push(l);
arrayCSV.push([n, l]);
});
destinationRecipient = i2pRecipient.getPublicKey();

console.log(`TestI2pSamRawBenchmark - Starting & running for ${this.minutes}mins / ${Date.now()}`);
let sentMsgs = 0;
const intervalSender = setInterval(async () => {
i2pSender.send(destinationRecipient, Buffer.from(Date.now().toString()));
sentMsgs++;
}, this.interval);

await TestI2pSamRawBenchmark.wait(Math.floor(this.interval / 2.1));

const intervalRecipient = setInterval(async () => {
i2pRecipient.send(destinationSender, Buffer.from(Date.now().toString()));
sentMsgs++;
}, this.interval);

let n: number = 0;
const fCSV = fs.openSync(this.pathCSV, 'a');
while (n++ < this.minutes) {
await TestI2pSamRawBenchmark.wait(60000);
// write csv
arrayCSV.forEach((a) => {
fs.writeSync(fCSV, a.join(',') + '\r\n');
});
arrayCSV = [];
console.log(`TestI2pSamRawBenchmark - ${n} / sent ${sentMsgs} messages`);
}

fs.closeSync(fCSV);
clearInterval(intervalSender);
clearInterval(intervalRecipient);
i2pSender.close();
i2pRecipient.close();

console.log(`TestI2pSamRawBenchmark - sent ${sentMsgs} messages / ${Date.now()}`);
console.log(`TestI2pSamRawBenchmark - arrived: ${((messageReceived / sentMsgs) * 100).toFixed(1)}%`);

// latency distribution
const a: Array<number> = arrayPerformance.sort((a, b) => a - b);
console.log('TestI2pSamRawBenchmark - Latency, min: ' + a[0]);
console.log('TestI2pSamRawBenchmark - Latency, 1st quartile: ' + a[Math.floor(a.length / 4)]);
console.log('TestI2pSamRawBenchmark - Latency, median: ' + a[Math.floor(a.length / 2)]);
console.log('TestI2pSamRawBenchmark - Latency, 3rd quartile: ' + a[Math.floor((a.length / 4) * 3)]);
console.log('TestI2pSamRawBenchmark - Latency, max: ' + a[a.length - 1]);
}

static async wait(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
}

const b = new TestI2pSamRawBenchmark(5);
await b.run();
10 changes: 10 additions & 0 deletions test/benchmark/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"declaration": false,
"outDir": "../compiled-benchmark"
},
"include": [
"./**/*.ts"
]
}
File renamed without changes.
2 changes: 2 additions & 0 deletions test/compiled-lib/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!.gitignore
2 changes: 2 additions & 0 deletions test/data/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!.gitignore
File renamed without changes.
2 changes: 1 addition & 1 deletion test/config.spec.ts → test/lib/config.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import { suite, test } from '@testdeck/mocha';
import { expect } from 'chai';
import { Config, Configuration } from '../lib/index.js';
import { Config, Configuration } from '../../lib/index.js';

@suite
class TestConfig {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import { suite, test, slow, timeout } from '@testdeck/mocha';
import { expect } from 'chai';
import { createDatagram, I2pSamDatagram } from '../lib/index.js';
import { createDatagram, I2pSamDatagram } from '../../lib/index.js';

const SAM_HOST = process.env.SAM_HOST || '172.19.74.11';
const SAM_PORT_TCP = Number(process.env.SAM_PORT_TCP) || 7656;
Expand All @@ -35,8 +35,6 @@ class TestI2pSamDatagram {
async send() {
let messageCounterA = 0;
let messageCounterB = 0;
const arrayPerformanceA: Array<number> = [];
const arrayPerformanceB: Array<number> = [];

let destinationSender = '';
let destinationRecipient = '';
Expand All @@ -51,9 +49,8 @@ class TestI2pSamDatagram {
hostForward: SAM_LISTEN_FORWARD,
},
})
).on('data', (msg: Buffer) => {
).on('data', () => {
messageCounterA++;
arrayPerformanceA.push(Date.now() - Number(msg.toString()));
});
destinationSender = i2pSender.getPublicKey();

Expand All @@ -67,14 +64,12 @@ class TestI2pSamDatagram {
hostForward: SAM_LISTEN_FORWARD,
},
})
).on('data', (msg: Buffer) => {
).on('data', () => {
messageCounterB++;
arrayPerformanceB.push(Date.now() - Number(msg.toString()));
});
destinationRecipient = i2pRecipient.getPublicKey();

console.log('Start sending data...');
console.log(Date.now());
console.log(Date.now() + ' - start sending data...');
let sentMsgs = 0;
const intervalSender = setInterval(async () => {
i2pSender.send(destinationRecipient, Buffer.from(Date.now().toString()));
Expand All @@ -89,20 +84,14 @@ class TestI2pSamDatagram {
while (!(messageCounterA >= 10 && messageCounterB >= 10)) {
await TestI2pSamDatagram.wait(100);
}
console.log(Date.now());
console.log('Total Sent: ' + sentMsgs);
console.log(Date.now() + ' - total Sent: ' + sentMsgs);
console.log('Arrived: ' + Math.round(((messageCounterA + messageCounterB) / sentMsgs) * 1000) / 10 + '%');

clearInterval(intervalSender);
clearInterval(intervalRecipient);
i2pSender.close();
i2pRecipient.close();

console.log('messageCounterA ' + messageCounterA);
console.log(arrayPerformanceA);
console.log('messageCounterB ' + messageCounterB);
console.log(arrayPerformanceB);

expect(messageCounterA).not.to.be.equal(0);
expect(messageCounterB).not.to.be.equal(0);
}
Expand Down
Loading

0 comments on commit 97e9ffc

Please sign in to comment.