Skip to content

Commit

Permalink
Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
ivov committed Apr 24, 2024
1 parent d6d7efb commit d0be040
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 110 deletions.
1 change: 1 addition & 0 deletions packages/cli/src/benchmark/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const BACKEND_BASE_URL = 'http://localhost:5678';
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ApplicationError } from 'n8n-workflow';
export class DuplicateHookError extends ApplicationError {
constructor(hookName: 'beforeEach' | 'afterEach', filePath: string) {
super(
`Duplicate \`${hookName}\` hook found in benchmarking suite \`${filePath}\`. Please define a single \`${hookName}\` hook for this suite.`,
`Duplicate \`${hookName}\` hook found at \`${filePath}\`. Please define a single \`${hookName}\` hook for this file.`,
{ level: 'warning' },
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { ApplicationError } from 'n8n-workflow';

export class UnsupportedDatabaseError extends ApplicationError {
constructor() {
super('Currently only sqlite is supported for benchmarking', { level: 'warning' });
super(
'Currently only sqlite is supported for benchmarking. Please ensure DB_TYPE is set to `sqlite`',
{ level: 'warning' },
);
}
}
109 changes: 4 additions & 105 deletions packages/cli/src/benchmark/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,108 +1,7 @@
import 'reflect-metadata';
import path from 'node:path';
import type Bench from 'tinybench';
import { assert } from 'n8n-workflow';
import glob from 'fast-glob';
import callsites from 'callsites';
import type { Suites, Task, Callback } from './types';
import { DuplicateHookError } from './errors/duplicate-hook.error';
import { DuplicateSuiteError } from './errors/duplicate-suite.error';

const suites: Suites = {};

export async function collectSuites() {
const files = await glob('**/*.suite.js', {
cwd: path.join('dist', 'benchmark'),
absolute: true,
});

for (const f of files) {
await import(f);
}

return suites;
}

export function registerSuites(bench: Bench) {
for (const { hooks, tasks } of Object.values(suites)) {
/**
* In tinybench, `beforeAll` and `afterAll` refer to all iterations of
* a single task, while `beforeEach` and `afterEach` refer to each iteration.
*
* In jest and vitest, `beforeAll` and `afterAll` refer to all tests in a suite,
* while `beforeEach` and `afterEach` refer to each individual test.
*
* We rename tinybench's hooks to prevent confusion from this difference.
*/
const options: Record<string, Callback> = {};

if (hooks.beforeEach) options.beforeAll = hooks.beforeEach;
if (hooks.afterEach) options.afterAll = hooks.afterEach;

for (const t of tasks) {
bench.add(t.name, t.operation, options);
}
}
}

function suiteFilePath() {
const filePath = callsites()
.map((site) => site.getFileName())
.filter((site): site is string => site !== null)
.find((site) => site.endsWith('.suite.js'));

assert(filePath !== undefined);

return filePath;
}

export function suite(suiteName: string, suiteFn: () => void) {
const filePath = suiteFilePath();

if (suites[filePath]) throw new DuplicateSuiteError(filePath);

suites[filePath] = { name: suiteName, hooks: {}, tasks: [] };

suiteFn();
}

export function task(taskName: string, operation: Task['operation']) {
const filePath = suiteFilePath();

suites[filePath].tasks.push({
name: suites[filePath].name + ' ' + taskName,
operation,
});
}

// @TODO: Rename next two utils to dismbiguate?

/**
* Setup step to run once before all iterations of each benchmarking task in a suite.
*/
export function beforeEach(fn: Callback) {
const filePath = suiteFilePath();

if (suites[filePath]?.hooks.beforeEach) {
throw new DuplicateHookError('beforeEach', filePath);
}

suites[filePath].hooks.beforeEach = fn;
}

/**
* Teardown step to run once after all iterations of each benchmarking task in a suite.
*/
export function afterEach(fn: Callback) {
const filePath = suiteFilePath();

if (suites[filePath]?.hooks.afterEach) {
throw new DuplicateHookError('afterEach', filePath);
}

suites[filePath].hooks.afterEach = fn;
}

export const BACKEND_BASE_URL = 'http://localhost:5678';

export { BACKEND_BASE_URL } from './constants';
export { suite, task, beforeEach, afterEach, collectSuites, registerSuites } from './registration';
export * as hooks from './hooks';
export type { Suites } from './types';
export { UnsupportedDatabaseError } from './errors/unsupported-db.error';
105 changes: 105 additions & 0 deletions packages/cli/src/benchmark/lib/registration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import 'reflect-metadata';
import path from 'node:path';
import type Bench from 'tinybench';
import { assert } from 'n8n-workflow';
import glob from 'fast-glob';
import callsites from 'callsites';
import type { Suites, Task, Callback } from './types';
import { DuplicateHookError } from './errors/duplicate-hook.error';
import { DuplicateSuiteError } from './errors/duplicate-suite.error';

const suites: Suites = {};

export async function collectSuites() {
const files = await glob('**/*.suite.js', {
cwd: path.join('dist', 'benchmark'),
absolute: true,
});

for (const f of files) {
await import(f);
}

return suites;
}

export function registerSuites(bench: Bench) {
for (const { hooks, tasks } of Object.values(suites)) {
/**
* In tinybench, `beforeAll` and `afterAll` refer to all iterations of
* a single task, while `beforeEach` and `afterEach` refer to each iteration.
*
* In jest and vitest, `beforeAll` and `afterAll` refer to all tests in a suite,
* while `beforeEach` and `afterEach` refer to each individual test.
*
* We rename tinybench's hooks to prevent confusion from this difference.
*/
const options: Record<string, Callback> = {};

if (hooks.beforeEach) options.beforeAll = hooks.beforeEach;
if (hooks.afterEach) options.afterAll = hooks.afterEach;

for (const t of tasks) {
bench.add(t.name, t.operation, options);
}
}
}

function suiteFilePath() {
const filePath = callsites()
.map((site) => site.getFileName())
.filter((site): site is string => site !== null)
.find((site) => site.endsWith('.suite.js'));

assert(filePath !== undefined);

return filePath;
}

// @TODO: Support async suiteFn
export function suite(suiteName: string, suiteFn: () => void) {
const filePath = suiteFilePath();

if (suites[filePath]) throw new DuplicateSuiteError(filePath);

suites[filePath] = { name: suiteName, hooks: {}, tasks: [] };

suiteFn();
}

export function task(taskName: string, operation: Task['operation']) {
const filePath = suiteFilePath();

suites[filePath].tasks.push({
name: suites[filePath].name + ' ' + taskName,
operation,
});
}

// @TODO: Rename `beforeEach` and `afteEach` to dismbiguate? e.g. `beforeEachTask`, `afterEachTask`

/**
* Setup step to run once before all iterations of each benchmarking task in a suite.
*/
export function beforeEach(fn: Callback) {
const filePath = suiteFilePath();

if (suites[filePath]?.hooks.beforeEach) {
throw new DuplicateHookError('beforeEach', filePath);
}

suites[filePath].hooks.beforeEach = fn;
}

/**
* Teardown step to run once after all iterations of each benchmarking task in a suite.
*/
export function afterEach(fn: Callback) {
const filePath = suiteFilePath();

if (suites[filePath]?.hooks.afterEach) {
throw new DuplicateHookError('afterEach', filePath);
}

suites[filePath].hooks.afterEach = fn;
}
4 changes: 1 addition & 3 deletions packages/cli/src/benchmark/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import 'reflect-metadata';
import Container from 'typedi';
import config from '@/config';
import { Logger } from '@/Logger';
import * as hooks from './lib/hooks';
import { collectSuites, registerSuites } from './lib';
import { UnsupportedDatabaseError } from './lib/errors/unsupported-db.error';
import { collectSuites, registerSuites, UnsupportedDatabaseError, hooks } from './lib';

/* eslint-disable import/no-extraneous-dependencies */
import Bench from 'tinybench';
Expand Down

0 comments on commit d0be040

Please sign in to comment.