/** * 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(500); }); 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(500); }); 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(3000); }); });