mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 06:51:12 -05:00
276 lines
9.2 KiB
TypeScript
276 lines
9.2 KiB
TypeScript
/**
|
|
* Performance & Scalability Integration Tests
|
|
*
|
|
* Tests for system performance under various conditions.
|
|
*/
|
|
|
|
import { supabase } from '@/lib/supabaseClient';
|
|
import type { TestSuite, TestResult } from '../testRunner';
|
|
import { TestDataTracker } from '../TestDataTracker';
|
|
|
|
export const performanceTestSuite: TestSuite = {
|
|
id: 'performance',
|
|
name: 'Performance & Scalability',
|
|
description: 'Tests for system performance and query efficiency',
|
|
tests: [
|
|
{
|
|
id: 'perf-001',
|
|
name: 'Entity Query Performance',
|
|
description: 'Measures query performance for entity lists',
|
|
run: async (): Promise<TestResult> => {
|
|
const startTime = Date.now();
|
|
|
|
try {
|
|
// Test parks query performance
|
|
const parksStart = Date.now();
|
|
const { data: parks, error: parksError } = await supabase
|
|
.from('parks')
|
|
.select('id, name, slug, park_type, status')
|
|
.limit(50);
|
|
|
|
const parksDuration = Date.now() - parksStart;
|
|
|
|
if (parksError) throw new Error(`Parks query failed: ${parksError.message}`);
|
|
|
|
// Test rides query performance
|
|
const ridesStart = Date.now();
|
|
const { data: rides, error: ridesError } = await supabase
|
|
.from('rides')
|
|
.select('id, name, slug, category, status, park_id')
|
|
.limit(50);
|
|
|
|
const ridesDuration = Date.now() - ridesStart;
|
|
|
|
if (ridesError) throw new Error(`Rides query failed: ${ridesError.message}`);
|
|
|
|
// Test companies query performance
|
|
const companiesStart = Date.now();
|
|
const { data: companies, error: companiesError } = await supabase
|
|
.from('companies')
|
|
.select('id, name, slug, company_type')
|
|
.limit(50);
|
|
|
|
const companiesDuration = Date.now() - companiesStart;
|
|
|
|
if (companiesError) throw new Error(`Companies query failed: ${companiesError.message}`);
|
|
|
|
// Set performance thresholds (in milliseconds)
|
|
const threshold = 1000; // 1 second
|
|
const warnings: string[] = [];
|
|
|
|
if (parksDuration > threshold) {
|
|
warnings.push(`Parks query slow: ${parksDuration}ms`);
|
|
}
|
|
if (ridesDuration > threshold) {
|
|
warnings.push(`Rides query slow: ${ridesDuration}ms`);
|
|
}
|
|
if (companiesDuration > threshold) {
|
|
warnings.push(`Companies query slow: ${companiesDuration}ms`);
|
|
}
|
|
|
|
const totalDuration = Date.now() - startTime;
|
|
|
|
return {
|
|
id: 'perf-001',
|
|
name: 'Entity Query Performance',
|
|
suite: 'Performance & Scalability',
|
|
status: warnings.length === 0 ? 'pass' : 'fail',
|
|
duration: totalDuration,
|
|
timestamp: new Date().toISOString(),
|
|
error: warnings.length > 0 ? warnings.join('; ') : undefined,
|
|
details: {
|
|
parksDuration,
|
|
ridesDuration,
|
|
companiesDuration,
|
|
threshold,
|
|
parksCount: parks?.length || 0,
|
|
ridesCount: rides?.length || 0,
|
|
companiesCount: companies?.length || 0
|
|
}
|
|
};
|
|
|
|
} catch (error) {
|
|
return {
|
|
id: 'perf-001',
|
|
name: 'Entity Query Performance',
|
|
suite: 'Performance & Scalability',
|
|
status: 'fail',
|
|
duration: Date.now() - startTime,
|
|
error: error instanceof Error ? error.message : String(error),
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: 'perf-002',
|
|
name: 'Version History Query Performance',
|
|
description: 'Measures performance of version history queries',
|
|
run: async (): Promise<TestResult> => {
|
|
const startTime = Date.now();
|
|
const tracker = new TestDataTracker();
|
|
let parkId: string | null = null;
|
|
|
|
try {
|
|
// Create test park
|
|
const parkSlug = `test-park-perf-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
const { data: park, error: parkError } = await supabase
|
|
.from('parks')
|
|
.insert({
|
|
name: 'Test Park Performance',
|
|
slug: parkSlug,
|
|
park_type: 'theme_park',
|
|
status: 'operating',
|
|
is_test_data: true
|
|
})
|
|
.select('id')
|
|
.single();
|
|
|
|
if (parkError) throw parkError;
|
|
parkId = park.id;
|
|
tracker.track('parks', parkId);
|
|
|
|
// Create multiple versions (updates)
|
|
for (let i = 0; i < 10; i++) {
|
|
await supabase
|
|
.from('parks')
|
|
.update({ description: `Version ${i + 1}` })
|
|
.eq('id', parkId);
|
|
|
|
// Small delay to ensure versions are created
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
}
|
|
|
|
// Measure version history query
|
|
const versionStart = Date.now();
|
|
const { data: versions, error: versionError } = await supabase
|
|
.from('park_versions')
|
|
.select('version_id, version_number, change_type, created_at')
|
|
.eq('park_id', parkId)
|
|
.order('version_number', { ascending: false });
|
|
|
|
const versionDuration = Date.now() - versionStart;
|
|
|
|
if (versionError) throw new Error(`Version query failed: ${versionError.message}`);
|
|
|
|
// Performance threshold: 500ms for version history
|
|
const threshold = 500;
|
|
const isSlow = versionDuration > threshold;
|
|
|
|
const totalDuration = Date.now() - startTime;
|
|
|
|
return {
|
|
id: 'perf-002',
|
|
name: 'Version History Query Performance',
|
|
suite: 'Performance & Scalability',
|
|
status: isSlow ? 'fail' : 'pass',
|
|
duration: totalDuration,
|
|
timestamp: new Date().toISOString(),
|
|
error: isSlow ? `Version query took ${versionDuration}ms (threshold: ${threshold}ms)` : undefined,
|
|
details: {
|
|
versionDuration,
|
|
threshold,
|
|
versionsFound: versions?.length || 0,
|
|
isSlow
|
|
}
|
|
};
|
|
|
|
} catch (error) {
|
|
return {
|
|
id: 'perf-002',
|
|
name: 'Version History Query Performance',
|
|
suite: 'Performance & Scalability',
|
|
status: 'fail',
|
|
duration: Date.now() - startTime,
|
|
error: error instanceof Error ? error.message : String(error),
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
} finally {
|
|
await tracker.cleanup();
|
|
const remaining = await tracker.verifyCleanup();
|
|
if (remaining.length > 0) {
|
|
console.warn('perf-002 cleanup incomplete:', remaining);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: 'perf-003',
|
|
name: 'Database Function Performance',
|
|
description: 'Measures performance of database functions',
|
|
run: async (): Promise<TestResult> => {
|
|
const startTime = Date.now();
|
|
|
|
try {
|
|
const { data: userData } = await supabase.auth.getUser();
|
|
if (!userData.user) throw new Error('No authenticated user');
|
|
|
|
// Test is_moderator function performance
|
|
const modStart = Date.now();
|
|
const { data: isMod, error: modError } = await supabase
|
|
.rpc('is_moderator', {
|
|
_user_id: userData.user.id
|
|
});
|
|
|
|
const modDuration = Date.now() - modStart;
|
|
|
|
if (modError) throw modError;
|
|
|
|
// Test is_user_banned function performance
|
|
const banStart = Date.now();
|
|
const { data: isBanned, error: banError } = await supabase
|
|
.rpc('is_user_banned', {
|
|
p_user_id: userData.user.id
|
|
});
|
|
|
|
const banDuration = Date.now() - banStart;
|
|
|
|
if (banError) throw banError;
|
|
|
|
// Performance threshold: 200ms for simple functions
|
|
const threshold = 200;
|
|
const warnings: string[] = [];
|
|
|
|
if (modDuration > threshold) {
|
|
warnings.push(`is_moderator slow: ${modDuration}ms`);
|
|
}
|
|
if (banDuration > threshold) {
|
|
warnings.push(`is_user_banned slow: ${banDuration}ms`);
|
|
}
|
|
|
|
const totalDuration = Date.now() - startTime;
|
|
|
|
return {
|
|
id: 'perf-003',
|
|
name: 'Database Function Performance',
|
|
suite: 'Performance & Scalability',
|
|
status: warnings.length === 0 ? 'pass' : 'fail',
|
|
duration: totalDuration,
|
|
timestamp: new Date().toISOString(),
|
|
error: warnings.length > 0 ? warnings.join('; ') : undefined,
|
|
details: {
|
|
isModerator: isMod,
|
|
isBanned,
|
|
modDuration,
|
|
banDuration,
|
|
threshold,
|
|
allFast: warnings.length === 0
|
|
}
|
|
};
|
|
|
|
} catch (error) {
|
|
return {
|
|
id: 'perf-003',
|
|
name: 'Database Function Performance',
|
|
suite: 'Performance & Scalability',
|
|
status: 'fail',
|
|
duration: Date.now() - startTime,
|
|
error: error instanceof Error ? error.message : String(error),
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
}
|
|
}
|
|
}
|
|
]
|
|
};
|