From 2be2dcaea025b593e339cb4b409ee03f2008ec1d Mon Sep 17 00:00:00 2001 From: Daniel Salazar Date: Fri, 19 Dec 2025 19:57:22 -0800 Subject: [PATCH] Revert 2206 eric/25 cj0 more benchmarks (#2208) * Revert "perf: more benchmarks (2)" This reverts commit 2c60faf5166f7a1857e69a17125909ac8995deed. * Revert "perf: more benchmarks" This reverts commit d3c1fc31035eba74aff516723389febecf8f870a. --- .../src/filesystem/validation.bench.js | 173 ----------- .../services/file-cache/FileTracker.bench.js | 182 ----------- src/backend/src/util/context.bench.js | 216 ------------- src/backend/src/util/datautil.bench.js | 165 ---------- src/backend/src/util/identifier.bench.js | 163 ---------- src/backend/src/util/lockutil.bench.js | 283 ------------------ src/backend/src/util/opmath.bench.js | 122 -------- src/backend/src/util/pathutil.bench.js | 206 ------------- src/backend/src/util/structutil.bench.js | 240 --------------- src/backend/src/util/uuidfpe.bench.js | 162 ---------- 10 files changed, 1912 deletions(-) delete mode 100644 src/backend/src/filesystem/validation.bench.js delete mode 100644 src/backend/src/services/file-cache/FileTracker.bench.js delete mode 100644 src/backend/src/util/context.bench.js delete mode 100644 src/backend/src/util/datautil.bench.js delete mode 100644 src/backend/src/util/identifier.bench.js delete mode 100644 src/backend/src/util/lockutil.bench.js delete mode 100644 src/backend/src/util/opmath.bench.js delete mode 100644 src/backend/src/util/pathutil.bench.js delete mode 100644 src/backend/src/util/structutil.bench.js delete mode 100644 src/backend/src/util/uuidfpe.bench.js diff --git a/src/backend/src/filesystem/validation.bench.js b/src/backend/src/filesystem/validation.bench.js deleted file mode 100644 index 4790cca1..00000000 --- a/src/backend/src/filesystem/validation.bench.js +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2024-present Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import { bench, describe } from 'vitest'; -const { is_valid_path, is_valid_node_name } = require('./validation'); - -// Test data -const shortPath = '/home/user/file.txt'; -const mediumPath = '/home/user/documents/projects/puter/src/backend/file.js'; -const longPath = '/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/file.txt'; -const deeplyNestedPath = `${Array(50).fill('directory').join('/') }/file.txt`; - -const simpleFilename = 'document.pdf'; -const filenameWithSpaces = 'my document file.pdf'; -const filenameWithNumbers = 'report_2024_final_v2.xlsx'; -const maxLengthFilename = 'a'.repeat(255); - -// Invalid paths for testing rejection speed -const pathWithNull = '/home/user/\x00file.txt'; -const pathWithRTL = '/home/user/\u202Efile.txt'; -const pathWithLTR = '/home/user/\u200Efile.txt'; - -describe('is_valid_path - Valid paths', () => { - bench('short path (/home/user/file.txt)', () => { - is_valid_path(shortPath); - }); - - bench('medium path (~50 chars)', () => { - is_valid_path(mediumPath); - }); - - bench('long path (26 components)', () => { - is_valid_path(longPath); - }); - - bench('deeply nested path (50 components)', () => { - is_valid_path(`/${ deeplyNestedPath}`); - }); - - bench('relative path starting with dot', () => { - is_valid_path('./relative/path/to/file.txt'); - }); -}); - -describe('is_valid_path - With options', () => { - bench('with no_relative_components option', () => { - is_valid_path(mediumPath, { no_relative_components: true }); - }); - - bench('with allow_path_fragment option', () => { - is_valid_path('partial/path/fragment', { allow_path_fragment: true }); - }); - - bench('with both options', () => { - is_valid_path(shortPath, { no_relative_components: true, allow_path_fragment: true }); - }); -}); - -describe('is_valid_path - Invalid paths (rejection speed)', () => { - bench('path with null character', () => { - is_valid_path(pathWithNull); - }); - - bench('path with RTL override', () => { - is_valid_path(pathWithRTL); - }); - - bench('path with LTR mark', () => { - is_valid_path(pathWithLTR); - }); - - bench('empty string', () => { - is_valid_path(''); - }); - - bench('non-string input (number)', () => { - is_valid_path(12345); - }); - - bench('path not starting with / or .', () => { - is_valid_path('invalid/path/start'); - }); -}); - -describe('is_valid_node_name - Valid names', () => { - bench('simple filename', () => { - is_valid_node_name(simpleFilename); - }); - - bench('filename with spaces', () => { - is_valid_node_name(filenameWithSpaces); - }); - - bench('filename with numbers and underscores', () => { - is_valid_node_name(filenameWithNumbers); - }); - - bench('filename at max length (255 chars)', () => { - is_valid_node_name(maxLengthFilename); - }); - - bench('filename with multiple extensions', () => { - is_valid_node_name('archive.tar.gz'); - }); -}); - -describe('is_valid_node_name - Invalid names (rejection speed)', () => { - bench('name with forward slash', () => { - is_valid_node_name('invalid/name'); - }); - - bench('name with null character', () => { - is_valid_node_name('invalid\x00name'); - }); - - bench('single dot (.)', () => { - is_valid_node_name('.'); - }); - - bench('double dot (..)', () => { - is_valid_node_name('..'); - }); - - bench('only dots (...)', () => { - is_valid_node_name('...'); - }); - - bench('name exceeding max length', () => { - is_valid_node_name('a'.repeat(300)); - }); - - bench('non-string input', () => { - is_valid_node_name(null); - }); -}); - -describe('is_valid_path - Batch validation simulation', () => { - const paths = [ - '/home/user/file1.txt', - '/home/user/file2.txt', - '/home/user/documents/report.pdf', - '/var/log/system.log', - '/etc/config.json', - ]; - - bench('validate 5 paths sequentially', () => { - for ( const path of paths ) { - is_valid_path(path); - } - }); - - bench('validate 100 paths', () => { - for ( let i = 0; i < 100; i++ ) { - is_valid_path(paths[i % paths.length]); - } - }); -}); diff --git a/src/backend/src/services/file-cache/FileTracker.bench.js b/src/backend/src/services/file-cache/FileTracker.bench.js deleted file mode 100644 index 0e6a517a..00000000 --- a/src/backend/src/services/file-cache/FileTracker.bench.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2024-present Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import { bench, describe } from 'vitest'; -const { FileTracker } = require('./FileTracker'); - -// Helper to create a tracker with some access history -const createTrackerWithHistory = (accessCount) => { - const tracker = new FileTracker({ key: 'test-key', size: 1024 }); - for ( let i = 0; i < accessCount; i++ ) { - tracker.touch(); - } - return tracker; -}; - -describe('FileTracker - Construction', () => { - bench('create new FileTracker', () => { - new FileTracker({ key: `test-key-${ Math.random()}`, size: 1024 }); - }); - - bench('create multiple FileTrackers', () => { - for ( let i = 0; i < 100; i++ ) { - new FileTracker({ key: `key-${i}`, size: i * 100 }); - } - }); -}); - -describe('FileTracker - touch() operation', () => { - bench('touch() on new tracker', () => { - const tracker = new FileTracker({ key: 'test', size: 1024 }); - for ( let i = 0; i < 1000; i++ ) { - tracker.touch(); - } - }); - - bench('touch() with EWMA calculation', () => { - const tracker = new FileTracker({ key: 'test', size: 1024 }); - // Pre-warm with some touches - for ( let i = 0; i < 10; i++ ) { - tracker.touch(); - } - // Benchmark steady-state touches - for ( let i = 0; i < 1000; i++ ) { - tracker.touch(); - } - }); -}); - -describe('FileTracker - score calculation', () => { - bench('score on fresh tracker', () => { - const tracker = new FileTracker({ key: 'test', size: 1024 }); - tracker.touch(); // Need at least one touch for meaningful score - for ( let i = 0; i < 1000; i++ ) { - void tracker.score; - } - }); - - bench('score on tracker with history (10 accesses)', () => { - const tracker = createTrackerWithHistory(10); - for ( let i = 0; i < 1000; i++ ) { - void tracker.score; - } - }); - - bench('score on tracker with history (100 accesses)', () => { - const tracker = createTrackerWithHistory(100); - for ( let i = 0; i < 1000; i++ ) { - void tracker.score; - } - }); -}); - -describe('FileTracker - age calculation', () => { - bench('age getter', () => { - const tracker = new FileTracker({ key: 'test', size: 1024 }); - for ( let i = 0; i < 10000; i++ ) { - void tracker.age; - } - }); -}); - -describe('FileTracker - Cache eviction simulation', () => { - bench('compare scores of multiple trackers', () => { - // Simulate cache with 100 items - const trackers = []; - for ( let i = 0; i < 100; i++ ) { - const tracker = new FileTracker({ key: `file-${i}`, size: i * 100 }); - // Simulate varying access patterns - const accessCount = Math.floor(Math.random() * 20); - for ( let j = 0; j < accessCount; j++ ) { - tracker.touch(); - } - trackers.push(tracker); - } - - // Find lowest score (eviction candidate) - for ( let i = 0; i < 100; i++ ) { - let minScore = Infinity; - let evictCandidate = null; - for ( const tracker of trackers ) { - const score = tracker.score; - if ( score < minScore ) { - minScore = score; - evictCandidate = tracker; - } - } - } - }); - - bench('sort trackers by score (eviction ordering)', () => { - const trackers = []; - for ( let i = 0; i < 50; i++ ) { - const tracker = new FileTracker({ key: `file-${i}`, size: i * 100 }); - for ( let j = 0; j < i % 10; j++ ) { - tracker.touch(); - } - trackers.push(tracker); - } - - // Sort by score - for ( let i = 0; i < 10; i++ ) { - [...trackers].sort((a, b) => a.score - b.score); - } - }); -}); - -describe('FileTracker - Real-world access patterns', () => { - bench('hot file pattern (frequent access)', () => { - const tracker = new FileTracker({ key: 'hot-file', size: 1024 }); - for ( let i = 0; i < 1000; i++ ) { - tracker.touch(); - if ( i % 10 === 0 ) { - void tracker.score; - } - } - }); - - bench('cold file pattern (rare access)', () => { - const tracker = new FileTracker({ key: 'cold-file', size: 1024 }); - tracker.touch(); - for ( let i = 0; i < 1000; i++ ) { - void tracker.score; - void tracker.age; - } - }); - - bench('mixed access with score checks', () => { - const trackers = []; - for ( let i = 0; i < 20; i++ ) { - trackers.push(new FileTracker({ key: `file-${i}`, size: 1024 })); - } - - for ( let i = 0; i < 500; i++ ) { - // Random access - const idx = Math.floor(Math.random() * trackers.length); - trackers[idx].touch(); - - // Periodic eviction check - if ( i % 50 === 0 ) { - for ( const t of trackers ) { - void t.score; - } - } - } - }); -}); diff --git a/src/backend/src/util/context.bench.js b/src/backend/src/util/context.bench.js deleted file mode 100644 index 0b20b8f0..00000000 --- a/src/backend/src/util/context.bench.js +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (C) 2024-present Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import { bench, describe } from 'vitest'; -import { Context } from './context'; - -describe('Context - Creation', () => { - bench('create empty context', () => { - Context.create({}); - }); - - bench('create context with single value', () => { - Context.create({ user: 'testuser' }); - }); - - bench('create context with multiple values', () => { - Context.create({ - user: 'testuser', - requestId: '12345', - timestamp: Date.now(), - metadata: { key: 'value' }, - }); - }); - - bench('create 100 contexts', () => { - for ( let i = 0; i < 100; i++ ) { - Context.create({ index: i }); - } - }); -}); - -describe('Context - Sub-context creation', () => { - const parentContext = Context.create({ parent: 'value' }); - - bench('create sub-context (empty)', () => { - parentContext.sub({}); - }); - - bench('create sub-context with values', () => { - parentContext.sub({ child: 'childValue' }); - }); - - bench('create sub-context with name', () => { - parentContext.sub({}, 'named-context'); - }); - - bench('create deeply nested sub-contexts (5 levels)', () => { - let ctx = parentContext; - for ( let i = 0; i < 5; i++ ) { - ctx = ctx.sub({ level: i }); - } - }); - - bench('create deeply nested sub-contexts (10 levels)', () => { - let ctx = parentContext; - for ( let i = 0; i < 10; i++ ) { - ctx = ctx.sub({ level: i }); - } - }); -}); - -describe('Context - Get/Set operations', () => { - const ctx = Context.create({ - key1: 'value1', - key2: 'value2', - key3: { nested: 'object' }, - }); - - bench('get existing key', () => { - ctx.get('key1'); - }); - - bench('get non-existing key', () => { - ctx.get('nonexistent'); - }); - - bench('get nested object', () => { - ctx.get('key3'); - }); - - bench('set new value', () => { - ctx.set('dynamic', Math.random()); - }); - - bench('get/set cycle (100 operations)', () => { - for ( let i = 0; i < 100; i++ ) { - ctx.set(`key_${i}`, i); - ctx.get(`key_${i}`); - } - }); -}); - -describe('Context - Prototype chain lookup', () => { - // Create a deep context chain - let deepCtx = Context.create({ root: 'rootValue' }); - for ( let i = 0; i < 10; i++ ) { - deepCtx = deepCtx.sub({ [`level${i}`]: `value${i}` }); - } - - bench('get value from root (10 levels up)', () => { - deepCtx.get('root'); - }); - - bench('get value from middle (5 levels up)', () => { - deepCtx.get('level5'); - }); - - bench('get value from current level', () => { - deepCtx.get('level9'); - }); -}); - -describe('Context - arun async execution', () => { - const ctx = Context.create({ test: 'value' }); - - bench('arun with simple callback', async () => { - await ctx.arun(async () => { - return 'result'; - }); - }); - - bench('arun with Context.get inside', async () => { - await ctx.arun(async () => { - Context.get('test'); - return 'result'; - }); - }); - - bench('nested arun calls (3 levels)', async () => { - await ctx.arun(async () => { - const subCtx = Context.get().sub({ level: 1 }); - await subCtx.arun(async () => { - const subSubCtx = Context.get().sub({ level: 2 }); - await subSubCtx.arun(async () => { - return Context.get('level'); - }); - }); - }); - }); -}); - -describe('Context - abind', () => { - const ctx = Context.create({ bound: 'value' }); - - bench('create bound function', () => { - ctx.abind(() => 'result'); - }); - - bench('execute bound function', async () => { - const boundFn = ctx.abind(async () => Context.get('bound')); - await boundFn(); - }); -}); - -describe('Context - describe/debug', () => { - const ctx = Context.create({ test: 'value' }, 'test-context'); - const deepCtx = ctx.sub({ level: 1 }, 'sub1').sub({ level: 2 }, 'sub2'); - - bench('describe shallow context', () => { - ctx.describe(); - }); - - bench('describe deep context', () => { - deepCtx.describe(); - }); -}); - -describe('Context - unlink (memory cleanup)', () => { - bench('create and unlink context', () => { - const ctx = Context.create({ - user: 'test', - data: { large: 'object' }, - }); - ctx.unlink(); - }); -}); - -describe('Context - Real-world simulation', () => { - bench('HTTP request context lifecycle', async () => { - // Simulate creating a context for an HTTP request - const reqCtx = Context.create({ - req: { method: 'GET', path: '/api/test' }, - res: {}, - trace_request: 'uuid-here', - }, 'req'); - - await reqCtx.arun(async () => { - // Simulate middleware adding data - const ctx = Context.get(); - ctx.set('user', { id: 1, name: 'test' }); - - // Simulate sub-operation - const opCtx = ctx.sub({ operation: 'readFile' }); - await opCtx.arun(async () => { - Context.get('user'); - Context.get('operation'); - }); - }); - }); -}); diff --git a/src/backend/src/util/datautil.bench.js b/src/backend/src/util/datautil.bench.js deleted file mode 100644 index f3f21366..00000000 --- a/src/backend/src/util/datautil.bench.js +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2024-present Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import { bench, describe } from 'vitest'; -const { stringify_serializable_object, hash_serializable_object } = require('./datautil'); - -// Test data generators -const createFlatObject = (size) => { - const obj = {}; - for ( let i = 0; i < size; i++ ) { - obj[`key${i}`] = `value${i}`; - } - return obj; -}; - -const createNestedObject = (depth, breadth) => { - if ( depth === 0 ) { - return { leaf: 'value' }; - } - const obj = {}; - for ( let i = 0; i < breadth; i++ ) { - obj[`level${depth}_child${i}`] = createNestedObject(depth - 1, breadth); - } - return obj; -}; - -const createMixedObject = () => ({ - string: 'hello world', - number: 42, - boolean: true, - null: null, - array: [1, 2, 3, { nested: 'array' }], - nested: { - deep: { - value: 'found', - numbers: [1, 2, 3], - }, - }, -}); - -// Objects with different key orderings (should produce same hash) -const objA = { z: 1, a: 2, m: 3 }; -const objB = { a: 2, m: 3, z: 1 }; -const objC = { m: 3, z: 1, a: 2 }; - -describe('stringify_serializable_object - Flat objects', () => { - const small = createFlatObject(5); - const medium = createFlatObject(20); - const large = createFlatObject(100); - - bench('small flat object (5 keys)', () => { - stringify_serializable_object(small); - }); - - bench('medium flat object (20 keys)', () => { - stringify_serializable_object(medium); - }); - - bench('large flat object (100 keys)', () => { - stringify_serializable_object(large); - }); -}); - -describe('stringify_serializable_object - Nested objects', () => { - const shallow = createNestedObject(2, 3); // depth 2, 3 children each - const medium = createNestedObject(3, 3); // depth 3, 3 children each - const deep = createNestedObject(4, 2); // depth 4, 2 children each - - bench('shallow nested (depth=2, breadth=3)', () => { - stringify_serializable_object(shallow); - }); - - bench('medium nested (depth=3, breadth=3)', () => { - stringify_serializable_object(medium); - }); - - bench('deep nested (depth=4, breadth=2)', () => { - stringify_serializable_object(deep); - }); -}); - -describe('stringify_serializable_object - Mixed types', () => { - const mixed = createMixedObject(); - - bench('mixed type object', () => { - stringify_serializable_object(mixed); - }); - - bench('primitives', () => { - stringify_serializable_object('string'); - stringify_serializable_object(42); - stringify_serializable_object(true); - stringify_serializable_object(null); - stringify_serializable_object(undefined); - }); -}); - -describe('stringify_serializable_object - Key ordering normalization', () => { - bench('objects with different key orderings', () => { - // All should produce the same output - stringify_serializable_object(objA); - stringify_serializable_object(objB); - stringify_serializable_object(objC); - }); -}); - -describe('stringify_serializable_object vs JSON.stringify', () => { - const obj = createFlatObject(20); - - bench('stringify_serializable_object', () => { - stringify_serializable_object(obj); - }); - - bench('JSON.stringify (baseline, no key sorting)', () => { - JSON.stringify(obj); - }); - - bench('JSON.stringify with sorted keys (manual)', () => { - const sortedObj = {}; - Object.keys(obj).sort().forEach(k => { - sortedObj[k] = obj[k]; - }); - JSON.stringify(sortedObj); - }); -}); - -describe('hash_serializable_object', () => { - const small = createFlatObject(5); - const medium = createFlatObject(20); - const mixed = createMixedObject(); - - bench('hash small object', () => { - hash_serializable_object(small); - }); - - bench('hash medium object', () => { - hash_serializable_object(medium); - }); - - bench('hash mixed object', () => { - hash_serializable_object(mixed); - }); - - bench('hash objects with different key orderings (should be equal)', () => { - hash_serializable_object(objA); - hash_serializable_object(objB); - hash_serializable_object(objC); - }); -}); diff --git a/src/backend/src/util/identifier.bench.js b/src/backend/src/util/identifier.bench.js deleted file mode 100644 index b634c83e..00000000 --- a/src/backend/src/util/identifier.bench.js +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2024-present Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import { bench, describe } from 'vitest'; -const { generate_identifier, generate_random_code } = require('./identifier'); - -describe('generate_identifier - Basic generation', () => { - bench('generate single identifier (default separator)', () => { - generate_identifier(); - }); - - bench('generate identifier with hyphen separator', () => { - generate_identifier('-'); - }); - - bench('generate identifier with empty separator', () => { - generate_identifier(''); - }); - - bench('generate 100 identifiers', () => { - for ( let i = 0; i < 100; i++ ) { - generate_identifier(); - } - }); - - bench('generate 1000 identifiers', () => { - for ( let i = 0; i < 1000; i++ ) { - generate_identifier(); - } - }); -}); - -describe('generate_identifier - With custom RNG', () => { - // Seeded pseudo-random for reproducibility - const seededRng = () => { - let seed = 12345; - return () => { - seed = (seed * 1103515245 + 12345) & 0x7fffffff; - return seed / 0x7fffffff; - }; - }; - - bench('generate with Math.random (default)', () => { - generate_identifier('_', Math.random); - }); - - bench('generate with seeded RNG', () => { - const rng = seededRng(); - generate_identifier('_', rng); - }); -}); - -describe('generate_random_code - Various lengths', () => { - bench('generate 4-char code', () => { - generate_random_code(4); - }); - - bench('generate 8-char code', () => { - generate_random_code(8); - }); - - bench('generate 16-char code', () => { - generate_random_code(16); - }); - - bench('generate 32-char code', () => { - generate_random_code(32); - }); - - bench('generate 64-char code', () => { - generate_random_code(64); - }); -}); - -describe('generate_random_code - Custom character sets', () => { - const numericOnly = '0123456789'; - const hexChars = '0123456789ABCDEF'; - const alphaLower = 'abcdefghijklmnopqrstuvwxyz'; - const fullAlphanumeric = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - - bench('numeric only (10 chars)', () => { - generate_random_code(10, { chars: numericOnly }); - }); - - bench('hex chars (16 chars)', () => { - generate_random_code(16, { chars: hexChars }); - }); - - bench('lowercase alpha (10 chars)', () => { - generate_random_code(10, { chars: alphaLower }); - }); - - bench('full alphanumeric (16 chars)', () => { - generate_random_code(16, { chars: fullAlphanumeric }); - }); -}); - -describe('generate_random_code - Batch generation', () => { - bench('generate 100 codes (8 chars each)', () => { - for ( let i = 0; i < 100; i++ ) { - generate_random_code(8); - } - }); - - bench('generate 1000 codes (8 chars each)', () => { - for ( let i = 0; i < 1000; i++ ) { - generate_random_code(8); - } - }); -}); - -describe('Comparison with alternatives', () => { - bench('generate_identifier', () => { - generate_identifier(); - }); - - bench('generate_random_code (8 chars)', () => { - generate_random_code(8); - }); - - bench('Math.random().toString(36).slice(2, 10)', () => { - Math.random().toString(36).slice(2, 10); - }); - - bench('Date.now().toString(36)', () => { - Date.now().toString(36); - }); -}); - -describe('Real-world usage patterns', () => { - bench('generate username suggestion', () => { - // Pattern: adjective_noun_number - generate_identifier('_'); - }); - - bench('generate session token (32 chars)', () => { - generate_random_code(32); - }); - - bench('generate verification code (6 chars, numeric)', () => { - generate_random_code(6, { chars: '0123456789' }); - }); - - bench('generate file suffix (8 chars)', () => { - generate_random_code(8); - }); -}); diff --git a/src/backend/src/util/lockutil.bench.js b/src/backend/src/util/lockutil.bench.js deleted file mode 100644 index bd7413f5..00000000 --- a/src/backend/src/util/lockutil.bench.js +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (C) 2024-present Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import { bench, describe } from 'vitest'; -const { RWLock } = require('./lockutil'); - -describe('RWLock - Creation', () => { - bench('create RWLock', () => { - new RWLock(); - }); - - bench('create 100 RWLocks', () => { - for ( let i = 0; i < 100; i++ ) { - new RWLock(); - } - }); -}); - -describe('RWLock - Mode checking', () => { - const lock = new RWLock(); - - bench('check effective_mode (idle)', () => { - void lock.effective_mode; - }); -}); - -describe('RWLock - Read locks (no contention)', () => { - bench('single rlock/unlock cycle', async () => { - const lock = new RWLock(); - const handle = await lock.rlock(); - handle.unlock(); - }); - - bench('10 sequential rlock/unlock cycles', async () => { - const lock = new RWLock(); - for ( let i = 0; i < 10; i++ ) { - const handle = await lock.rlock(); - handle.unlock(); - } - }); - - bench('concurrent read locks (5 readers)', async () => { - const lock = new RWLock(); - const handles = await Promise.all([ - lock.rlock(), - lock.rlock(), - lock.rlock(), - lock.rlock(), - lock.rlock(), - ]); - for ( const handle of handles ) { - handle.unlock(); - } - }); - - bench('concurrent read locks (10 readers)', async () => { - const lock = new RWLock(); - const promises = []; - for ( let i = 0; i < 10; i++ ) { - promises.push(lock.rlock()); - } - const handles = await Promise.all(promises); - for ( const handle of handles ) { - handle.unlock(); - } - }); -}); - -describe('RWLock - Write locks (no contention)', () => { - bench('single wlock/unlock cycle', async () => { - const lock = new RWLock(); - const handle = await lock.wlock(); - handle.unlock(); - }); - - bench('10 sequential wlock/unlock cycles', async () => { - const lock = new RWLock(); - for ( let i = 0; i < 10; i++ ) { - const handle = await lock.wlock(); - handle.unlock(); - } - }); -}); - -describe('RWLock - Mixed read/write patterns', () => { - bench('read then write then read', async () => { - const lock = new RWLock(); - - const r1 = await lock.rlock(); - r1.unlock(); - - const w = await lock.wlock(); - w.unlock(); - - const r2 = await lock.rlock(); - r2.unlock(); - }); - - bench('write then multiple reads', async () => { - const lock = new RWLock(); - - const w = await lock.wlock(); - w.unlock(); - - const handles = await Promise.all([ - lock.rlock(), - lock.rlock(), - lock.rlock(), - ]); - for ( const h of handles ) { - h.unlock(); - } - }); - - bench('alternating read/write (10 cycles)', async () => { - const lock = new RWLock(); - for ( let i = 0; i < 10; i++ ) { - if ( i % 2 === 0 ) { - const h = await lock.rlock(); - h.unlock(); - } else { - const h = await lock.wlock(); - h.unlock(); - } - } - }); -}); - -describe('RWLock - Contention patterns', () => { - bench('readers waiting for writer', async () => { - const lock = new RWLock(); - - // Writer goes first - const writePromise = (async () => { - const h = await lock.wlock(); - // Simulate work - h.unlock(); - })(); - - // Readers queue up - const readerPromises = []; - for ( let i = 0; i < 5; i++ ) { - readerPromises.push((async () => { - const h = await lock.rlock(); - h.unlock(); - })()); - } - - await Promise.all([writePromise, ...readerPromises]); - }); - - bench('writer waiting for readers', async () => { - const lock = new RWLock(); - - // Readers go first - const readerPromises = []; - for ( let i = 0; i < 5; i++ ) { - readerPromises.push((async () => { - const h = await lock.rlock(); - h.unlock(); - })()); - } - - // Writer queues up - const writePromise = (async () => { - const h = await lock.wlock(); - h.unlock(); - })(); - - await Promise.all([...readerPromises, writePromise]); - }); -}); - -describe('RWLock - Queue behavior', () => { - bench('check_queue_ with empty queue', () => { - const lock = new RWLock(); - lock.check_queue_(); - }); -}); - -describe('RWLock - on_empty_ callback', () => { - bench('set on_empty_ callback', () => { - const lock = new RWLock(); - lock.on_empty_ = () => { - }; - }); - - bench('trigger on_empty_ via lock cycle', async () => { - const lock = new RWLock(); - lock.on_empty_ = () => { - }; - - const h = await lock.rlock(); - h.unlock(); - // on_empty_ should be called - }); -}); - -describe('Real-world patterns', () => { - bench('cache read pattern (10 concurrent readers)', async () => { - const lock = new RWLock(); - const promises = []; - - for ( let i = 0; i < 10; i++ ) { - promises.push((async () => { - const h = await lock.rlock(); - // Simulate cache read - h.unlock(); - })()); - } - - await Promise.all(promises); - }); - - bench('cache invalidation pattern', async () => { - const lock = new RWLock(); - - // Some readers first - const readerPromises = []; - for ( let i = 0; i < 3; i++ ) { - readerPromises.push((async () => { - const h = await lock.rlock(); - h.unlock(); - })()); - } - - // Invalidation (write) - const invalidatePromise = (async () => { - const h = await lock.wlock(); - // Simulate cache clear - h.unlock(); - })(); - - // New readers after invalidation - for ( let i = 0; i < 3; i++ ) { - readerPromises.push((async () => { - const h = await lock.rlock(); - h.unlock(); - })()); - } - - await Promise.all([...readerPromises, invalidatePromise]); - }); - - bench('file access pattern (mostly reads, occasional write)', async () => { - const lock = new RWLock(); - const operations = []; - - for ( let i = 0; i < 20; i++ ) { - if ( i % 5 === 0 ) { - // Write every 5th operation - operations.push((async () => { - const h = await lock.wlock(); - h.unlock(); - })()); - } else { - // Read otherwise - operations.push((async () => { - const h = await lock.rlock(); - h.unlock(); - })()); - } - } - - await Promise.all(operations); - }); -}); diff --git a/src/backend/src/util/opmath.bench.js b/src/backend/src/util/opmath.bench.js deleted file mode 100644 index c37000c8..00000000 --- a/src/backend/src/util/opmath.bench.js +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2024-present Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import { bench, describe } from 'vitest'; -const { EWMA, MovingMode, TimeWindow, normalize } = require('./opmath'); - -describe('EWMA - Exponential Weighted Moving Average', () => { - bench('EWMA put() with constant alpha', () => { - const ewma = new EWMA({ initial: 0, alpha: 0.2 }); - for ( let i = 0; i < 1000; i++ ) { - ewma.put(Math.random() * 100); - } - }); - - bench('EWMA put() with function alpha', () => { - const ewma = new EWMA({ initial: 0, alpha: () => 0.2 }); - for ( let i = 0; i < 1000; i++ ) { - ewma.put(Math.random() * 100); - } - }); - - bench('EWMA get() after many puts', () => { - const ewma = new EWMA({ initial: 0, alpha: 0.2 }); - for ( let i = 0; i < 100; i++ ) { - ewma.put(i); - } - for ( let i = 0; i < 1000; i++ ) { - ewma.get(); - } - }); -}); - -describe('MovingMode - Mode calculation with sliding window', () => { - bench('MovingMode put() with window_size=30', () => { - const mode = new MovingMode({ initial: 0, window_size: 30 }); - for ( let i = 0; i < 1000; i++ ) { - mode.put(Math.floor(Math.random() * 10)); - } - }); - - bench('MovingMode put() with window_size=100', () => { - const mode = new MovingMode({ initial: 0, window_size: 100 }); - for ( let i = 0; i < 1000; i++ ) { - mode.put(Math.floor(Math.random() * 10)); - } - }); - - bench('MovingMode with high cardinality values', () => { - const mode = new MovingMode({ initial: 0, window_size: 50 }); - for ( let i = 0; i < 1000; i++ ) { - mode.put(Math.floor(Math.random() * 1000)); - } - }); - - bench('MovingMode with low cardinality values', () => { - const mode = new MovingMode({ initial: 0, window_size: 50 }); - for ( let i = 0; i < 1000; i++ ) { - mode.put(Math.floor(Math.random() * 3)); - } - }); -}); - -describe('TimeWindow - Time-based sliding window', () => { - bench('TimeWindow add() and get()', () => { - let fakeTime = 0; - const tw = new TimeWindow({ - window_duration: 1000, - reducer: values => values.reduce((a, b) => a + b, 0), - now: () => fakeTime, - }); - for ( let i = 0; i < 1000; i++ ) { - fakeTime += 10; - tw.add(Math.random()); - } - }); - - bench('TimeWindow with stale entry removal', () => { - let fakeTime = 0; - const tw = new TimeWindow({ - window_duration: 100, - reducer: values => values.length, - now: () => fakeTime, - }); - for ( let i = 0; i < 1000; i++ ) { - fakeTime += 50; // Fast time progression causes stale removal - tw.add(i); - tw.get(); - } - }); -}); - -describe('normalize - Exponential normalization', () => { - bench('normalize() single value', () => { - for ( let i = 0; i < 10000; i++ ) { - normalize({ high_value: 0.001 }, Math.random()); - } - }); - - bench('normalize() with varying high_value', () => { - const high_values = [0.001, 0.01, 0.1, 1, 10]; - for ( let i = 0; i < 10000; i++ ) { - const hv = high_values[i % high_values.length]; - normalize({ high_value: hv }, Math.random() * 100); - } - }); -}); diff --git a/src/backend/src/util/pathutil.bench.js b/src/backend/src/util/pathutil.bench.js deleted file mode 100644 index 561e6b19..00000000 --- a/src/backend/src/util/pathutil.bench.js +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2024-present Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import { bench, describe } from 'vitest'; -const { PathBuilder } = require('./pathutil'); - -describe('PathBuilder - Creation', () => { - bench('create PathBuilder (default)', () => { - PathBuilder.create(); - }); - - bench('create PathBuilder (puterfs mode)', () => { - PathBuilder.create({ puterfs: true }); - }); - - bench('create via new', () => { - new PathBuilder(); - }); -}); - -describe('PathBuilder - Static add', () => { - bench('static add single fragment', () => { - PathBuilder.add('directory'); - }); - - bench('static add with traversal prevention', () => { - PathBuilder.add('../../../etc/passwd'); - }); - - bench('static add with allow_traversal', () => { - PathBuilder.add('../parent', { allow_traversal: true }); - }); -}); - -describe('PathBuilder - Static resolve', () => { - bench('resolve simple path', () => { - PathBuilder.resolve('/home/user/file.txt'); - }); - - bench('resolve relative path', () => { - PathBuilder.resolve('./relative/path'); - }); - - bench('resolve with puterfs', () => { - PathBuilder.resolve('/home/user/file.txt', { puterfs: true }); - }); - - bench('resolve complex path', () => { - PathBuilder.resolve('/a/b/c/../d/./e/f'); - }); -}); - -describe('PathBuilder - Instance add', () => { - bench('add single fragment', () => { - const builder = PathBuilder.create(); - builder.add('directory'); - }); - - bench('add multiple fragments (chain)', () => { - PathBuilder.create() - .add('home') - .add('user') - .add('documents') - .add('file.txt'); - }); - - bench('add 10 fragments', () => { - const builder = PathBuilder.create(); - for ( let i = 0; i < 10; i++ ) { - builder.add(`dir${i}`); - } - }); -}); - -describe('PathBuilder - Traversal prevention', () => { - bench('sanitize parent traversal (..)', () => { - PathBuilder.create().add('..'); - }); - - bench('sanitize multiple parent traversals', () => { - PathBuilder.create().add('../../..'); - }); - - bench('sanitize mixed traversal patterns', () => { - PathBuilder.create().add('../foo/../../bar/../baz'); - }); - - bench('sanitize with backslash traversal', () => { - PathBuilder.create().add('..\\..\\..\\etc\\passwd'); - }); - - bench('allow_traversal option', () => { - PathBuilder.create().add('../parent/child', { allow_traversal: true }); - }); -}); - -describe('PathBuilder - Build', () => { - bench('build empty path', () => { - PathBuilder.create().build(); - }); - - bench('build simple path', () => { - PathBuilder.create() - .add('home') - .add('user') - .build(); - }); - - bench('build long path', () => { - const builder = PathBuilder.create(); - for ( let i = 0; i < 20; i++ ) { - builder.add(`directory${i}`); - } - builder.build(); - }); -}); - -describe('PathBuilder - Complete workflows', () => { - bench('create, add, build (simple)', () => { - PathBuilder.create() - .add('home') - .add('user') - .add('file.txt') - .build(); - }); - - bench('create, add, build (with sanitization)', () => { - PathBuilder.create() - .add('../attempt') - .add('actual') - .add('path') - .build(); - }); - - bench('puterfs path building', () => { - PathBuilder.create({ puterfs: true }) - .add('username') - .add('documents') - .add('report.pdf') - .build(); - }); -}); - -describe('PathBuilder - Batch operations', () => { - const fragments = ['home', 'user', 'documents', 'projects', 'puter']; - - bench('build 10 paths', () => { - for ( let i = 0; i < 10; i++ ) { - const builder = PathBuilder.create(); - for ( const frag of fragments ) { - builder.add(frag); - } - builder.build(); - } - }); - - bench('build 100 paths', () => { - for ( let i = 0; i < 100; i++ ) { - const builder = PathBuilder.create(); - for ( const frag of fragments ) { - builder.add(frag); - } - builder.build(); - } - }); -}); - -describe('Comparison with native path operations', () => { - const path = require('path'); - - bench('PathBuilder.resolve', () => { - PathBuilder.resolve('/home/user/file.txt'); - }); - - bench('native path.resolve', () => { - path.resolve('/home/user/file.txt'); - }); - - bench('PathBuilder chain vs path.join', () => { - PathBuilder.create() - .add('home') - .add('user') - .add('file.txt') - .build(); - }); - - bench('native path.join', () => { - path.join('home', 'user', 'file.txt'); - }); -}); diff --git a/src/backend/src/util/structutil.bench.js b/src/backend/src/util/structutil.bench.js deleted file mode 100644 index f2621054..00000000 --- a/src/backend/src/util/structutil.bench.js +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (C) 2024-present Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import { bench, describe } from 'vitest'; -const { cart_product, apply_keys } = require('./structutil'); - -describe('cart_product - Small inputs', () => { - bench('2 keys, 2 values each', () => { - cart_product({ - a: [1, 2], - b: ['x', 'y'], - }); - }); - - bench('3 keys, 2 values each', () => { - cart_product({ - a: [1, 2], - b: ['x', 'y'], - c: [true, false], - }); - }); - - bench('2 keys, 3 values each', () => { - cart_product({ - a: [1, 2, 3], - b: ['x', 'y', 'z'], - }); - }); -}); - -describe('cart_product - Medium inputs', () => { - bench('4 keys, 2 values each (16 combinations)', () => { - cart_product({ - a: [1, 2], - b: [3, 4], - c: [5, 6], - d: [7, 8], - }); - }); - - bench('3 keys, 3 values each (27 combinations)', () => { - cart_product({ - a: [1, 2, 3], - b: [4, 5, 6], - c: [7, 8, 9], - }); - }); - - bench('5 keys, 2 values each (32 combinations)', () => { - cart_product({ - a: [1, 2], - b: [3, 4], - c: [5, 6], - d: [7, 8], - e: [9, 10], - }); - }); -}); - -describe('cart_product - Large inputs', () => { - bench('3 keys, 5 values each (125 combinations)', () => { - cart_product({ - a: [1, 2, 3, 4, 5], - b: [6, 7, 8, 9, 10], - c: [11, 12, 13, 14, 15], - }); - }); - - bench('4 keys, 4 values each (256 combinations)', () => { - cart_product({ - a: [1, 2, 3, 4], - b: [5, 6, 7, 8], - c: [9, 10, 11, 12], - d: [13, 14, 15, 16], - }); - }); - - bench('6 keys, 2 values each (64 combinations)', () => { - cart_product({ - a: [1, 2], - b: [3, 4], - c: [5, 6], - d: [7, 8], - e: [9, 10], - f: [11, 12], - }); - }); -}); - -describe('cart_product - Single values', () => { - bench('3 keys, 1 value each (1 combination)', () => { - cart_product({ - a: 1, - b: 2, - c: 3, - }); - }); - - bench('mixed single and array values', () => { - cart_product({ - a: 1, - b: [2, 3], - c: 4, - d: [5, 6], - }); - }); -}); - -describe('cart_product - Edge cases', () => { - bench('empty object', () => { - cart_product({}); - }); - - bench('single key with array', () => { - cart_product({ - only: [1, 2, 3, 4, 5], - }); - }); - - bench('many keys with single values', () => { - cart_product({ - a: 1, - b: 2, - c: 3, - d: 4, - e: 5, - f: 6, - g: 7, - h: 8, - i: 9, - j: 10, - }); - }); -}); - -describe('apply_keys - Basic operations', () => { - const keys = ['a', 'b', 'c']; - - bench('apply to single entry', () => { - apply_keys(keys, [1, 2, 3]); - }); - - bench('apply to 5 entries', () => { - apply_keys(keys, - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - [10, 11, 12], - [13, 14, 15]); - }); - - bench('apply to 10 entries', () => { - const entries = []; - for ( let i = 0; i < 10; i++ ) { - entries.push([i * 3, i * 3 + 1, i * 3 + 2]); - } - apply_keys(keys, ...entries); - }); -}); - -describe('apply_keys - Varying key counts', () => { - bench('2 keys', () => { - apply_keys(['a', 'b'], [1, 2], [3, 4], [5, 6]); - }); - - bench('5 keys', () => { - apply_keys(['a', 'b', 'c', 'd', 'e'], - [1, 2, 3, 4, 5], - [6, 7, 8, 9, 10]); - }); - - bench('10 keys', () => { - const keys = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']; - const entry = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - apply_keys(keys, entry, entry, entry); - }); -}); - -describe('Combined cart_product + apply_keys workflow', () => { - bench('generate and label small product', () => { - const product = cart_product({ - size: ['small', 'medium', 'large'], - color: ['red', 'blue'], - }); - apply_keys(['size', 'color'], ...product); - }); - - bench('generate and label medium product', () => { - const product = cart_product({ - a: [1, 2, 3], - b: [4, 5, 6], - c: [7, 8, 9], - }); - apply_keys(['a', 'b', 'c'], ...product); - }); -}); - -describe('Real-world configuration generation', () => { - bench('test matrix generation (browser x OS)', () => { - const matrix = cart_product({ - browser: ['chrome', 'firefox', 'safari'], - os: ['windows', 'macos', 'linux'], - }); - apply_keys(['browser', 'os'], ...matrix); - }); - - bench('feature flag combinations', () => { - cart_product({ - featureA: [true, false], - featureB: [true, false], - featureC: [true, false], - featureD: [true, false], - }); - }); - - bench('API endpoint parameter combinations', () => { - const combinations = cart_product({ - method: ['GET', 'POST'], - auth: ['none', 'token', 'session'], - format: ['json', 'xml'], - }); - apply_keys(['method', 'auth', 'format'], ...combinations); - }); -}); diff --git a/src/backend/src/util/uuidfpe.bench.js b/src/backend/src/util/uuidfpe.bench.js deleted file mode 100644 index ac773c73..00000000 --- a/src/backend/src/util/uuidfpe.bench.js +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2024-present Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import { bench, describe } from 'vitest'; -const { UUIDFPE } = require('./uuidfpe'); -const crypto = require('crypto'); - -// Test data -const testKey = Buffer.from('0123456789abcdef'); // 16-byte key -const testUuid = '550e8400-e29b-41d4-a716-446655440000'; -const fpe = new UUIDFPE(testKey); -const encryptedUuid = fpe.encrypt(testUuid); - -// Pre-generate UUIDs for batch tests -const uuids = []; -for ( let i = 0; i < 100; i++ ) { - uuids.push(crypto.randomUUID()); -} - -describe('UUIDFPE - Construction', () => { - bench('create UUIDFPE instance', () => { - new UUIDFPE(testKey); - }); - - bench('create with random key', () => { - const key = crypto.randomBytes(16); - new UUIDFPE(key); - }); -}); - -describe('UUIDFPE - Static utilities', () => { - bench('uuidToBuffer', () => { - UUIDFPE.uuidToBuffer(testUuid); - }); - - bench('bufferToUuid', () => { - const buffer = Buffer.from('550e8400e29b41d4a716446655440000', 'hex'); - UUIDFPE.bufferToUuid(buffer); - }); - - bench('round-trip buffer conversion', () => { - const buffer = UUIDFPE.uuidToBuffer(testUuid); - UUIDFPE.bufferToUuid(buffer); - }); -}); - -describe('UUIDFPE - Encryption', () => { - bench('encrypt single UUID', () => { - fpe.encrypt(testUuid); - }); - - bench('encrypt 10 UUIDs', () => { - for ( let i = 0; i < 10; i++ ) { - fpe.encrypt(uuids[i]); - } - }); - - bench('encrypt 100 UUIDs', () => { - for ( const uuid of uuids ) { - fpe.encrypt(uuid); - } - }); -}); - -describe('UUIDFPE - Decryption', () => { - bench('decrypt single UUID', () => { - fpe.decrypt(encryptedUuid); - }); - - // Pre-encrypt for decryption benchmarks - const encryptedUuids = uuids.map(uuid => fpe.encrypt(uuid)); - - bench('decrypt 10 UUIDs', () => { - for ( let i = 0; i < 10; i++ ) { - fpe.decrypt(encryptedUuids[i]); - } - }); - - bench('decrypt 100 UUIDs', () => { - for ( const encrypted of encryptedUuids ) { - fpe.decrypt(encrypted); - } - }); -}); - -describe('UUIDFPE - Round-trip', () => { - bench('encrypt then decrypt (single)', () => { - const encrypted = fpe.encrypt(testUuid); - fpe.decrypt(encrypted); - }); - - bench('encrypt then decrypt (10 UUIDs)', () => { - for ( let i = 0; i < 10; i++ ) { - const encrypted = fpe.encrypt(uuids[i]); - fpe.decrypt(encrypted); - } - }); -}); - -describe('UUIDFPE - Comparison with alternatives', () => { - bench('UUIDFPE encrypt', () => { - fpe.encrypt(testUuid); - }); - - bench('native crypto.randomUUID (for comparison)', () => { - crypto.randomUUID(); - }); - - bench('SHA256 hash of UUID (for comparison)', () => { - crypto.createHash('sha256').update(testUuid).digest('hex'); - }); -}); - -describe('UUIDFPE - Different keys', () => { - const keys = []; - for ( let i = 0; i < 10; i++ ) { - keys.push(crypto.randomBytes(16)); - } - - bench('encrypt with 10 different keys', () => { - for ( const key of keys ) { - const instance = new UUIDFPE(key); - instance.encrypt(testUuid); - } - }); -}); - -describe('Real-world patterns', () => { - bench('obfuscate user ID', () => { - // Simulate hiding internal UUID from external API - fpe.encrypt(testUuid); - }); - - bench('de-obfuscate incoming ID', () => { - // Simulate receiving obfuscated ID and decrypting - fpe.decrypt(encryptedUuid); - }); - - bench('API response transformation (10 items)', () => { - // Simulate transforming a list of items with obfuscated IDs - uuids.slice(0, 10).map(uuid => ({ - id: fpe.encrypt(uuid), - name: 'item', - })); - }); -});