diff --git a/package-lock.json b/package-lock.json index 6a02ff99e..60e1e8cec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@idrinth/api-bench", - "version": "1.2.2", + "version": "1.2.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f45dfc980..3a58ac563 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@idrinth/api-bench", "description": "A library to benchmark apis, no matter if rest or soap", "license": "MIT", - "version": "1.2.2", + "version": "1.2.3", "homepage": "https://github.com/Idrinth/api-bench", "repository": { "type": "git", diff --git a/src/executor.ts b/src/executor.ts index 4e1c97b67..c22a9e182 100644 --- a/src/executor.ts +++ b/src/executor.ts @@ -18,6 +18,7 @@ import { } from './logger/logger'; import Reporter from './reporter/reporter'; import * as Progress from 'cli-progress'; +import validateTasks from './validate-tasks'; const EMPTY = 0; @@ -43,9 +44,7 @@ const executor = ( logger: Logger, Worker: WorkerConstructor, ): void => { - if (tasks.length === 0 || repetitions < 1 || threads < 1) { - throw new Error("Can't measure no tasks."); - } + validateTasks(repetitions, threads, tasks,); const validator: Thread = new Worker('./worker/validator.js',); const calculator: Thread = new Worker('./worker/calculator.js',); const bar = new Progress.SingleBar({ diff --git a/src/validate-tasks.ts b/src/validate-tasks.ts new file mode 100644 index 000000000..b1694b057 --- /dev/null +++ b/src/validate-tasks.ts @@ -0,0 +1,33 @@ +import { + Task, +} from './task'; + +const EMPTY = 0; + +const noDuplicateIDs = (tasks: Array,) => { + const ids: Array = []; + for (const task of tasks) { + if (ids.includes(task.id,)) { + throw new Error(`The id ${ task.id } is shared.`,); + } + ids.push(task.id,); + } +}; +const executableAmount = ( + repetitions: number, + threads: number, + tasks: Array, +): void => { + if (tasks.length === EMPTY || repetitions <= EMPTY || threads <= EMPTY) { + throw new Error('Can\'t measure no tasks.',); + } +}; + +export default function validateTasks( + repetitions: number, + threads: number, + tasks: Array, +): void { + executableAmount(repetitions, threads, tasks,); + noDuplicateIDs(tasks,); +} diff --git a/test/executor.ts b/test/executor.ts index a14e273d3..17e1137a6 100644 --- a/test/executor.ts +++ b/test/executor.ts @@ -1,29 +1,56 @@ -import executor, { Thread } from '../src/executor'; +import executor, { + Thread, +} from '../src/executor'; import { expect, } from 'chai'; import 'mocha'; -import { NullLogger } from '../src/logger/null-logger'; -import { Result } from '../src/result'; -import { ResultSet } from '../src/result-set'; -import { FinishedSet } from '../src/finished-set'; -import { PinoWrapper } from '../src/logger/pino-wrapper'; -import { Task } from '../src/task'; -const pino = require('pino',); - -class FakeResult implements Result,ResultSet,FinishedSet { +import { + NullLogger, +} from '../src/logger/null-logger'; +import { + Result, +} from '../src/result'; +import { + FinishedSet, +} from '../src/finished-set'; +import { + Task, +} from '../src/task'; +import { + ValidationResult, +} from '../src/validation-result'; + +// eslint-disable-next-line @typescript-eslint/no-empty-function +const NOOP = () => {}; +const NONE = 0; + +class FakeResult implements Result, ValidationResult, FinishedSet { + + public duration; + public id = 'some-id'; - public errors = 1; - public count = 0; - public avg100 = 9; - public median100 = 9; - public max100 = 9; - public min100 = 9; - public avg80 = 9; - public median80 = 9; - public max80 = 9; - public min80 = 9; - public duration = 9; + + public errors: number; + + public count: number; + + public avg100: number; + + public median100: number; + + public max100: number; + + public min100: number; + + public avg80: number; + + public median80: number; + + public max80: number; + + public min80: number; + public response = { headers: {}, cookies: {}, @@ -31,67 +58,117 @@ class FakeResult implements Result,ResultSet,FinishedSet { uri: '', status: 202, }; + public validators = []; - public durations = [9]; + + public durations; + public msgs = {}; + + success = true; + + public constructor() { + const requests = 1; + this.errors = requests; + this.count = requests; + const duration = 9; + this.duration = duration; + this.avg100 = duration; + this.avg80 = duration; + this.durations = [ duration, ]; + this.max100 = duration; + this.max80 = duration; + this.min100 = duration; + this.min80 = duration; + this.median100 = duration; + this.median80 = duration; + } + public add() { - this.count++; - }; -}; + this.count ++; + } +} class FakeWorker implements Thread { private handler; + public static built = {}; + public static terminated = {}; + private result = new FakeResult(); - public constructor(private path: string) - { - FakeWorker.built[path] = FakeWorker.built[path] || 0; - FakeWorker.built[path]++; + + public constructor(private path: string,) { + FakeWorker.built[path] = FakeWorker.built[path] || NONE; + FakeWorker.built[path] ++; } - public on(type: string, callable: (a: unknown)=>void): void - { + + public on(type: string, callable: (a: unknown)=>void,): void { this.handler = callable; } - public postMessage(a: unknown): void { + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public postMessage(a: unknown,): void { const c = this.handler; const result = this.result; - setTimeout(() => c(result), 1); + const next = 1; + setTimeout(() => c(result,), next,); } - public terminate(): void - { - FakeWorker.terminated[this.path] = FakeWorker.terminated[this.path] || 0; - FakeWorker.terminated[this.path]++; + + public terminate(): void { + FakeWorker.terminated[this.path] = FakeWorker.terminated[this.path] || NONE; + FakeWorker.terminated[this.path] ++; } } describe('executor', () => { + const repeats = 2; + const threads = 3; + const tasks = [ { + id: 'test', + }, ]; + const once = 1; it('should be a function', () => { expect(executor,).to.be.a('function',); },); - it ('should not try to execute no tasks(0 tasks)', () => { - expect(() => executor(3, 2, [], () => {}, new NullLogger(), FakeWorker)).to.throw("Can't measure no tasks."); - }); - it ('should not try to execute no tasks(0 repeats)', () => { - expect(() => executor(0, 2, [ {id: 'test'}], () => {}, new NullLogger(), FakeWorker)).to.throw("Can't measure no tasks."); - }); - it ('should not try to execute no tasks (0 threads)', () => { - expect(() => executor(3, 0, [ {id: 'test'}], () => {}, new NullLogger(), FakeWorker)).to.throw("Can't measure no tasks."); - }); - it ('should execute all tasks', (done) => { - executor(3, 2, [ {id: 'test'}], () => done(), new NullLogger(), FakeWorker); - }); - it ('should have build the right workers', () => { - expect(FakeWorker.built).to.deep.equal({ - "./worker/calculator.js": 1, - "./worker/validator.js": 1, - "./worker/webrequest.js": 3, - }); - }); - it ('should have shut down the right workers', () => { - expect(FakeWorker.terminated).to.deep.equal({ - "./worker/calculator.js": 1, - "./worker/validator.js": 1, - "./worker/webrequest.js": 3, - }); - }); + it('should not try to execute no tasks(0 tasks)', () => { + expect( + () => executor(threads, repeats, [], NOOP, new NullLogger(), FakeWorker,), + ).to.throw('Can\'t measure no tasks.',); + },); + it('should not try to execute no tasks(0 threads)', () => { + expect( + () => executor(NONE, repeats, tasks, NOOP, new NullLogger(), FakeWorker,), + ).to.throw('Can\'t measure no tasks.',); + },); + it('should not try to execute no tasks (0 repeats)', () => { + expect( + () => executor(threads, NONE, tasks, NOOP, new NullLogger(), FakeWorker,), + ).to.throw('Can\'t measure no tasks.',); + },); + it('should execute all tasks', (done,) => { + expect( + () => executor( + threads, + repeats, + tasks, + () => done(), + new NullLogger(), + FakeWorker, + ), + ).to.not.throw(); + },); + it('should have build the right workers', () => { + expect(FakeWorker.built,).to.deep.equal({ + './worker/calculator.js': once, + './worker/validator.js': once, + './worker/webrequest.js': threads, + },); + },); + it('should have shut down the right workers', () => { + expect(FakeWorker.terminated,).to.deep.equal({ + './worker/calculator.js': once, + './worker/validator.js': once, + './worker/webrequest.js': threads, + },); + },); },); diff --git a/test/validate-tasks.ts b/test/validate-tasks.ts new file mode 100644 index 000000000..5f02ce964 --- /dev/null +++ b/test/validate-tasks.ts @@ -0,0 +1,54 @@ +import 'mocha'; +import { + expect, +} from 'chai'; +import validateTasks from '../src/validate-tasks'; +import { + Task, +} from '../src/task'; + +describe('validateTasks', () => { + it('should be a function', () => { + expect(validateTasks,).to.be.a('function',); + },); + const threads = 33; + const repetitions = 100; + const tasks = [ { + id: 'test', + }, ]; + const repeatedIdTasks = [ + { + id: 'test', + }, + { + id: '2.', + }, + { + id: 'test', + }, + ]; + const none = 0; + it('it should throw if none executlable is given (0 threads)', () => { + expect(() => validateTasks(repetitions, none, tasks,),).to.throw( + 'Can\'t measure no tasks.' + ); + },); + it('it should throw if none executlable is given (0 repetitions)', () => { + expect(() => validateTasks(none, threads, tasks,),).to.throw( + 'Can\'t measure no tasks.' + ); + },); + it('it should throw if none executlable is given (0 tasks)', () => { + expect(() => validateTasks(repetitions, threads, [],),).to.throw( + 'Can\'t measure no tasks.' + ); + },); + it('it should throw if task ids are duplicated', () => { + expect( + () => validateTasks(repetitions, threads, repeatedIdTasks,), + ).to.throw(`The id test is shared.`,); + },); + it('it should not throw if given valid arguments', () => { + expect(() => validateTasks(repetitions, threads, tasks,),).to.not.throw(); + },); +},);