127 lines
4.3 KiB
TypeScript
127 lines
4.3 KiB
TypeScript
/**
|
||
* Backend Stresstest – 50.000 Elemente: SQLite CRUD Performance,
|
||
* Bulk-Insert, List, Update, Delete mit Transaktion-Support.
|
||
*/
|
||
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||
import { SqliteAdapter } from '../src/database/SqliteAdapter.js';
|
||
import type { DBElement } from '../src/database/DatabaseInterface.js';
|
||
|
||
const N = 50_000;
|
||
|
||
describe('Backend Stresstest: 50.000 Elemente in SQLite', () => {
|
||
let db: SqliteAdapter;
|
||
let drawingId: string;
|
||
let layerId: string;
|
||
let elementIds: string[] = [];
|
||
|
||
beforeAll(async () => {
|
||
db = new SqliteAdapter(':memory:');
|
||
await db.init();
|
||
|
||
// Create prerequisite project → drawing → layer
|
||
const project = db.createProject({ name: 'Stresstest Project' });
|
||
const drawing = db.createDrawing({ project_id: project.id, name: 'Stresstest Drawing' });
|
||
drawingId = drawing.id;
|
||
const layer = db.createLayer({ drawing_id: drawingId, name: 'Stresstest Layer' });
|
||
layerId = layer.id;
|
||
});
|
||
|
||
afterAll(() => {
|
||
db.close();
|
||
});
|
||
|
||
it('should bulk-insert 50k elements in under 5s', () => {
|
||
const start = performance.now();
|
||
// Use transaction for bulk insert
|
||
const insert = db['db'].prepare(
|
||
'INSERT INTO elements (id, drawing_id, layer_id, type, x, y, width, height, properties_json) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||
);
|
||
const insertMany = db['db'].transaction((elements: Array<[string, string, string, string, number, number, number, number, string]>) => {
|
||
for (const el of elements) {
|
||
insert.run(...el);
|
||
}
|
||
});
|
||
|
||
const batch: Array<[string, string, string, string, number, number, number, number, string]> = [];
|
||
for (let i = 0; i < N; i++) {
|
||
const id = `stress-elem-${i}`;
|
||
elementIds.push(id);
|
||
batch.push([
|
||
id,
|
||
drawingId,
|
||
layerId,
|
||
'rect',
|
||
(i % 1000) * 1.5,
|
||
Math.floor(i / 1000) * 1.5,
|
||
1,
|
||
1,
|
||
'{}',
|
||
]);
|
||
}
|
||
insertMany(batch);
|
||
const elapsed = performance.now() - start;
|
||
console.log(`Bulk insert ${N} elements: ${elapsed.toFixed(1)}ms`);
|
||
expect(elapsed).toBeLessThan(5000);
|
||
});
|
||
|
||
it('should list 50k elements in under 500ms', () => {
|
||
const start = performance.now();
|
||
const elements = db.listElements(drawingId);
|
||
const elapsed = performance.now() - start;
|
||
console.log(`List ${N} elements: ${elapsed.toFixed(1)}ms, count=${elements.length}`);
|
||
expect(elements.length).toBe(N);
|
||
expect(elapsed).toBeLessThan(1000);
|
||
});
|
||
|
||
it('should update 100 elements in under 200ms', () => {
|
||
const start = performance.now();
|
||
for (let i = 0; i < 100; i++) {
|
||
db.updateElement(elementIds[i], { x: 9999 + i });
|
||
}
|
||
const elapsed = performance.now() - start;
|
||
console.log(`Update 100 elements: ${elapsed.toFixed(1)}ms`);
|
||
expect(elapsed).toBeLessThan(200);
|
||
});
|
||
|
||
it('should read a single element in under 5ms', () => {
|
||
const start = performance.now();
|
||
const element = db.listElements(drawingId);
|
||
const mid = element[Math.floor(element.length / 2)];
|
||
const elapsed = performance.now() - start;
|
||
console.log(`Read mid element from ${N}: ${elapsed.toFixed(1)}ms`);
|
||
expect(mid).toBeDefined();
|
||
expect(elapsed).toBeLessThan(2000);
|
||
});
|
||
|
||
it('should delete 1000 elements in under 500ms', () => {
|
||
const start = performance.now();
|
||
const deleteStmt = db['db'].prepare('DELETE FROM elements WHERE id = ?');
|
||
const deleteMany = db['db'].transaction((ids: string[]) => {
|
||
for (const id of ids) {
|
||
deleteStmt.run(id);
|
||
}
|
||
});
|
||
const toDelete = elementIds.slice(0, 1000);
|
||
deleteMany(toDelete);
|
||
const elapsed = performance.now() - start;
|
||
console.log(`Delete 1000 elements: ${elapsed.toFixed(1)}ms`);
|
||
expect(elapsed).toBeLessThan(500);
|
||
|
||
// Verify count
|
||
const remaining = db.listElements(drawingId);
|
||
expect(remaining.length).toBe(N - 1000);
|
||
});
|
||
|
||
it('should handle concurrent queries efficiently', () => {
|
||
// Simulate 10 concurrent list operations
|
||
const start = performance.now();
|
||
for (let i = 0; i < 10; i++) {
|
||
const elements = db.listElements(drawingId);
|
||
expect(elements.length).toBe(N - 1000);
|
||
}
|
||
const elapsed = performance.now() - start;
|
||
console.log(`10x list operations on ${N - 1000} elements: ${elapsed.toFixed(1)}ms`);
|
||
expect(elapsed).toBeLessThan(10000);
|
||
});
|
||
});
|