update
This commit is contained in:
@ -0,0 +1,504 @@
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
import * as plugins from '../../../ts/plugins.ts';
|
||||
import { EInvoice } from '../../../ts/classes.xinvoice.ts';
|
||||
import { CorpusLoader } from '../../helpers/corpus.loader.ts';
|
||||
import { PerformanceTracker } from '../../helpers/performance.tracker.ts';
|
||||
|
||||
const testTimeout = 600000; // 10 minutes timeout for performance testing
|
||||
|
||||
// VAL-12: Validation Performance
|
||||
// Tests validation performance characteristics including speed, memory usage,
|
||||
// and scalability under various load conditions
|
||||
|
||||
tap.test('VAL-12: Validation Performance - Single Invoice Validation Speed', async (tools) => {
|
||||
const startTime = Date.now();
|
||||
|
||||
// Test validation speed for different invoice sizes
|
||||
const performanceTests = [
|
||||
{
|
||||
name: 'Minimal UBL Invoice',
|
||||
xml: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
|
||||
<ID>MIN-001</ID>
|
||||
<IssueDate>2024-01-01</IssueDate>
|
||||
<InvoiceTypeCode>380</InvoiceTypeCode>
|
||||
<DocumentCurrencyCode>EUR</DocumentCurrencyCode>
|
||||
<LegalMonetaryTotal>
|
||||
<PayableAmount currencyID="EUR">100.00</PayableAmount>
|
||||
</LegalMonetaryTotal>
|
||||
</Invoice>`,
|
||||
expectedMaxTime: 20 // 20ms max for minimal invoice
|
||||
},
|
||||
{
|
||||
name: 'Standard UBL Invoice',
|
||||
xml: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
|
||||
<ID>STD-001</ID>
|
||||
<IssueDate>2024-01-01</IssueDate>
|
||||
<InvoiceTypeCode>380</InvoiceTypeCode>
|
||||
<DocumentCurrencyCode>EUR</DocumentCurrencyCode>
|
||||
<AccountingSupplierParty>
|
||||
<Party>
|
||||
<PartyName><Name>Test Supplier</Name></PartyName>
|
||||
<PostalAddress>
|
||||
<StreetName>Test Street 1</StreetName>
|
||||
<CityName>Test City</CityName>
|
||||
<PostalZone>12345</PostalZone>
|
||||
<Country><IdentificationCode>DE</IdentificationCode></Country>
|
||||
</PostalAddress>
|
||||
</Party>
|
||||
</AccountingSupplierParty>
|
||||
<AccountingCustomerParty>
|
||||
<Party>
|
||||
<PartyName><Name>Test Customer</Name></PartyName>
|
||||
<PostalAddress>
|
||||
<StreetName>Customer Street 1</StreetName>
|
||||
<CityName>Customer City</CityName>
|
||||
<PostalZone>54321</PostalZone>
|
||||
<Country><IdentificationCode>DE</IdentificationCode></Country>
|
||||
</PostalAddress>
|
||||
</Party>
|
||||
</AccountingCustomerParty>
|
||||
<InvoiceLine>
|
||||
<ID>1</ID>
|
||||
<InvoicedQuantity unitCode="C62">1</InvoicedQuantity>
|
||||
<LineExtensionAmount currencyID="EUR">100.00</LineExtensionAmount>
|
||||
<Item><Name>Test Item</Name></Item>
|
||||
<Price><PriceAmount currencyID="EUR">100.00</PriceAmount></Price>
|
||||
</InvoiceLine>
|
||||
<TaxTotal>
|
||||
<TaxAmount currencyID="EUR">19.00</TaxAmount>
|
||||
</TaxTotal>
|
||||
<LegalMonetaryTotal>
|
||||
<LineExtensionAmount currencyID="EUR">100.00</LineExtensionAmount>
|
||||
<TaxExclusiveAmount currencyID="EUR">100.00</TaxExclusiveAmount>
|
||||
<TaxInclusiveAmount currencyID="EUR">119.00</TaxInclusiveAmount>
|
||||
<PayableAmount currencyID="EUR">119.00</PayableAmount>
|
||||
</LegalMonetaryTotal>
|
||||
</Invoice>`,
|
||||
expectedMaxTime: 50 // 50ms max for standard invoice
|
||||
}
|
||||
];
|
||||
|
||||
for (const test of performanceTests) {
|
||||
const times = [];
|
||||
const iterations = 10;
|
||||
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const iterationStart = Date.now();
|
||||
|
||||
try {
|
||||
const invoice = new EInvoice();
|
||||
await invoice.fromXmlString(test.xml);
|
||||
const validationResult = await invoice.validate();
|
||||
|
||||
const iterationTime = Date.now() - iterationStart;
|
||||
times.push(iterationTime);
|
||||
|
||||
// Ensure validation actually worked
|
||||
expect(validationResult).toBeTruthy();
|
||||
|
||||
} catch (error) {
|
||||
tools.log(`Validation failed for ${test.name}: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
const avgTime = times.reduce((a, b) => a + b, 0) / times.length;
|
||||
const minTime = Math.min(...times);
|
||||
const maxTime = Math.max(...times);
|
||||
const p95Time = times.sort((a, b) => a - b)[Math.floor(times.length * 0.95)];
|
||||
|
||||
tools.log(`${test.name} validation performance:`);
|
||||
tools.log(` Average: ${avgTime.toFixed(1)}ms`);
|
||||
tools.log(` Min: ${minTime}ms, Max: ${maxTime}ms`);
|
||||
tools.log(` P95: ${p95Time}ms`);
|
||||
|
||||
// Performance expectations
|
||||
expect(avgTime).toBeLessThan(test.expectedMaxTime);
|
||||
expect(p95Time).toBeLessThan(test.expectedMaxTime * 2);
|
||||
|
||||
PerformanceTracker.recordMetric(`validation-performance-${test.name.toLowerCase().replace(/\s+/g, '-')}`, avgTime);
|
||||
}
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
PerformanceTracker.recordMetric('validation-performance-single', duration);
|
||||
});
|
||||
|
||||
tap.test('VAL-12: Validation Performance - Concurrent Validation', { timeout: testTimeout }, async (tools) => {
|
||||
const startTime = Date.now();
|
||||
|
||||
// Test concurrent validation performance
|
||||
const testXml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
|
||||
<ID>CONCURRENT-001</ID>
|
||||
<IssueDate>2024-01-01</IssueDate>
|
||||
<InvoiceTypeCode>380</InvoiceTypeCode>
|
||||
<DocumentCurrencyCode>EUR</DocumentCurrencyCode>
|
||||
<LegalMonetaryTotal>
|
||||
<PayableAmount currencyID="EUR">100.00</PayableAmount>
|
||||
</LegalMonetaryTotal>
|
||||
</Invoice>`;
|
||||
|
||||
const concurrencyLevels = [1, 5, 10, 20];
|
||||
|
||||
for (const concurrency of concurrencyLevels) {
|
||||
const concurrentStart = Date.now();
|
||||
|
||||
const promises = [];
|
||||
for (let i = 0; i < concurrency; i++) {
|
||||
promises.push((async () => {
|
||||
const invoice = new EInvoice();
|
||||
await invoice.fromXmlString(testXml);
|
||||
return await invoice.validate();
|
||||
})());
|
||||
}
|
||||
|
||||
try {
|
||||
const results = await Promise.all(promises);
|
||||
const concurrentDuration = Date.now() - concurrentStart;
|
||||
|
||||
// Verify all validations succeeded
|
||||
for (const result of results) {
|
||||
expect(result).toBeTruthy();
|
||||
}
|
||||
|
||||
const avgTimePerValidation = concurrentDuration / concurrency;
|
||||
|
||||
tools.log(`Concurrent validation (${concurrency} parallel):`);
|
||||
tools.log(` Total time: ${concurrentDuration}ms`);
|
||||
tools.log(` Avg per validation: ${avgTimePerValidation.toFixed(1)}ms`);
|
||||
tools.log(` Throughput: ${(1000 / avgTimePerValidation).toFixed(1)} validations/sec`);
|
||||
|
||||
// Performance expectations
|
||||
expect(avgTimePerValidation).toBeLessThan(100); // 100ms max per validation
|
||||
expect(concurrentDuration).toBeLessThan(5000); // 5 seconds max total
|
||||
|
||||
PerformanceTracker.recordMetric(`validation-performance-concurrent-${concurrency}`, avgTimePerValidation);
|
||||
|
||||
} catch (error) {
|
||||
tools.log(`Concurrent validation failed at level ${concurrency}: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
const totalDuration = Date.now() - startTime;
|
||||
PerformanceTracker.recordMetric('validation-performance-concurrent', totalDuration);
|
||||
});
|
||||
|
||||
tap.test('VAL-12: Validation Performance - Large Invoice Handling', { timeout: testTimeout }, async (tools) => {
|
||||
const startTime = Date.now();
|
||||
|
||||
// Test performance with large invoices (many line items)
|
||||
const lineCounts = [1, 10, 50, 100];
|
||||
|
||||
for (const lineCount of lineCounts) {
|
||||
const largeInvoiceStart = Date.now();
|
||||
|
||||
// Generate invoice with multiple lines
|
||||
let invoiceLines = '';
|
||||
for (let i = 1; i <= lineCount; i++) {
|
||||
invoiceLines += `
|
||||
<InvoiceLine>
|
||||
<ID>${i}</ID>
|
||||
<InvoicedQuantity unitCode="C62">1</InvoicedQuantity>
|
||||
<LineExtensionAmount currencyID="EUR">10.00</LineExtensionAmount>
|
||||
<Item><Name>Item ${i}</Name></Item>
|
||||
<Price><PriceAmount currencyID="EUR">10.00</PriceAmount></Price>
|
||||
</InvoiceLine>`;
|
||||
}
|
||||
|
||||
const totalAmount = lineCount * 10;
|
||||
const taxAmount = totalAmount * 0.19;
|
||||
const totalWithTax = totalAmount + taxAmount;
|
||||
|
||||
const largeInvoiceXml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
|
||||
<ID>LARGE-${lineCount}-LINES</ID>
|
||||
<IssueDate>2024-01-01</IssueDate>
|
||||
<InvoiceTypeCode>380</InvoiceTypeCode>
|
||||
<DocumentCurrencyCode>EUR</DocumentCurrencyCode>
|
||||
${invoiceLines}
|
||||
<TaxTotal>
|
||||
<TaxAmount currencyID="EUR">${taxAmount.toFixed(2)}</TaxAmount>
|
||||
</TaxTotal>
|
||||
<LegalMonetaryTotal>
|
||||
<LineExtensionAmount currencyID="EUR">${totalAmount.toFixed(2)}</LineExtensionAmount>
|
||||
<TaxExclusiveAmount currencyID="EUR">${totalAmount.toFixed(2)}</TaxExclusiveAmount>
|
||||
<TaxInclusiveAmount currencyID="EUR">${totalWithTax.toFixed(2)}</TaxInclusiveAmount>
|
||||
<PayableAmount currencyID="EUR">${totalWithTax.toFixed(2)}</PayableAmount>
|
||||
</LegalMonetaryTotal>
|
||||
</Invoice>`;
|
||||
|
||||
try {
|
||||
const invoice = new EInvoice();
|
||||
await invoice.fromXmlString(largeInvoiceXml);
|
||||
const validationResult = await invoice.validate();
|
||||
|
||||
const largeInvoiceDuration = Date.now() - largeInvoiceStart;
|
||||
|
||||
expect(validationResult).toBeTruthy();
|
||||
|
||||
const timePerLine = largeInvoiceDuration / lineCount;
|
||||
|
||||
tools.log(`Large invoice validation (${lineCount} lines):`);
|
||||
tools.log(` Total time: ${largeInvoiceDuration}ms`);
|
||||
tools.log(` Time per line: ${timePerLine.toFixed(2)}ms`);
|
||||
|
||||
// Performance expectations scale with line count
|
||||
const maxExpectedTime = Math.max(100, lineCount * 2); // 2ms per line minimum
|
||||
expect(largeInvoiceDuration).toBeLessThan(maxExpectedTime);
|
||||
|
||||
PerformanceTracker.recordMetric(`validation-performance-large-${lineCount}-lines`, largeInvoiceDuration);
|
||||
|
||||
} catch (error) {
|
||||
tools.log(`Large invoice validation failed (${lineCount} lines): ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
const totalDuration = Date.now() - startTime;
|
||||
PerformanceTracker.recordMetric('validation-performance-large', totalDuration);
|
||||
});
|
||||
|
||||
tap.test('VAL-12: Validation Performance - Memory Usage Monitoring', async (tools) => {
|
||||
const startTime = Date.now();
|
||||
|
||||
// Monitor memory usage during validation
|
||||
const memoryBefore = process.memoryUsage();
|
||||
|
||||
const testXml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
|
||||
<ID>MEMORY-TEST-001</ID>
|
||||
<IssueDate>2024-01-01</IssueDate>
|
||||
<InvoiceTypeCode>380</InvoiceTypeCode>
|
||||
<DocumentCurrencyCode>EUR</DocumentCurrencyCode>
|
||||
<LegalMonetaryTotal>
|
||||
<PayableAmount currencyID="EUR">100.00</PayableAmount>
|
||||
</LegalMonetaryTotal>
|
||||
</Invoice>`;
|
||||
|
||||
// Perform multiple validations and monitor memory
|
||||
const iterations = 100;
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const invoice = new EInvoice();
|
||||
await invoice.fromXmlString(testXml);
|
||||
await invoice.validate();
|
||||
|
||||
// Force garbage collection periodically
|
||||
if (i % 20 === 0 && global.gc) {
|
||||
global.gc();
|
||||
}
|
||||
}
|
||||
|
||||
const memoryAfter = process.memoryUsage();
|
||||
|
||||
const heapGrowth = memoryAfter.heapUsed - memoryBefore.heapUsed;
|
||||
const rssGrowth = memoryAfter.rss - memoryBefore.rss;
|
||||
|
||||
tools.log(`Memory usage for ${iterations} validations:`);
|
||||
tools.log(` Heap growth: ${(heapGrowth / 1024 / 1024).toFixed(2)} MB`);
|
||||
tools.log(` RSS growth: ${(rssGrowth / 1024 / 1024).toFixed(2)} MB`);
|
||||
tools.log(` Heap per validation: ${(heapGrowth / iterations / 1024).toFixed(2)} KB`);
|
||||
|
||||
// Memory expectations
|
||||
const heapPerValidation = heapGrowth / iterations;
|
||||
expect(heapPerValidation).toBeLessThan(50 * 1024); // Less than 50KB per validation
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
PerformanceTracker.recordMetric('validation-performance-memory', duration);
|
||||
});
|
||||
|
||||
tap.test('VAL-12: Validation Performance - Corpus Performance Analysis', { timeout: testTimeout }, async (tools) => {
|
||||
const startTime = Date.now();
|
||||
|
||||
const performanceResults = [];
|
||||
let totalValidations = 0;
|
||||
let totalTime = 0;
|
||||
|
||||
try {
|
||||
// Test performance across different corpus categories
|
||||
const categories = ['UBL_XML_RECHNUNG', 'CII_XML_RECHNUNG'];
|
||||
|
||||
for (const category of categories) {
|
||||
const categoryStart = Date.now();
|
||||
let categoryValidations = 0;
|
||||
|
||||
try {
|
||||
const files = await CorpusLoader.getFiles(category);
|
||||
|
||||
for (const filePath of files.slice(0, 5)) { // Test first 5 files per category
|
||||
const fileStart = Date.now();
|
||||
|
||||
try {
|
||||
const invoice = new EInvoice();
|
||||
await invoice.fromFile(filePath);
|
||||
await invoice.validate();
|
||||
|
||||
const fileTime = Date.now() - fileStart;
|
||||
categoryValidations++;
|
||||
totalValidations++;
|
||||
totalTime += fileTime;
|
||||
|
||||
// Track file size impact on performance
|
||||
const stats = await plugins.fs.stat(filePath);
|
||||
const fileSizeKB = stats.size / 1024;
|
||||
|
||||
performanceResults.push({
|
||||
category,
|
||||
file: plugins.path.basename(filePath),
|
||||
time: fileTime,
|
||||
sizeKB: fileSizeKB,
|
||||
timePerKB: fileTime / fileSizeKB
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
tools.log(`Failed to process ${plugins.path.basename(filePath)}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
const categoryTime = Date.now() - categoryStart;
|
||||
const avgCategoryTime = categoryValidations > 0 ? categoryTime / categoryValidations : 0;
|
||||
|
||||
tools.log(`${category} performance:`);
|
||||
tools.log(` Files processed: ${categoryValidations}`);
|
||||
tools.log(` Total time: ${categoryTime}ms`);
|
||||
tools.log(` Avg per file: ${avgCategoryTime.toFixed(1)}ms`);
|
||||
|
||||
} catch (error) {
|
||||
tools.log(`Failed to process category ${category}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Analyze performance correlations
|
||||
if (performanceResults.length > 0) {
|
||||
const avgTime = totalTime / totalValidations;
|
||||
const avgSize = performanceResults.reduce((sum, r) => sum + r.sizeKB, 0) / performanceResults.length;
|
||||
const avgTimePerKB = performanceResults.reduce((sum, r) => sum + r.timePerKB, 0) / performanceResults.length;
|
||||
|
||||
tools.log(`Overall corpus performance analysis:`);
|
||||
tools.log(` Total validations: ${totalValidations}`);
|
||||
tools.log(` Average time: ${avgTime.toFixed(1)}ms`);
|
||||
tools.log(` Average file size: ${avgSize.toFixed(1)}KB`);
|
||||
tools.log(` Average time per KB: ${avgTimePerKB.toFixed(2)}ms/KB`);
|
||||
|
||||
// Performance expectations
|
||||
expect(avgTime).toBeLessThan(200); // 200ms max average
|
||||
expect(avgTimePerKB).toBeLessThan(10); // 10ms per KB max
|
||||
|
||||
// Find slowest files
|
||||
const slowestFiles = performanceResults
|
||||
.sort((a, b) => b.time - a.time)
|
||||
.slice(0, 3);
|
||||
|
||||
tools.log(`Slowest files:`);
|
||||
for (const file of slowestFiles) {
|
||||
tools.log(` ${file.file}: ${file.time}ms (${file.sizeKB.toFixed(1)}KB)`);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
tools.log(`Corpus performance analysis failed: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
|
||||
const totalDuration = Date.now() - startTime;
|
||||
PerformanceTracker.recordMetric('validation-performance-corpus', totalDuration);
|
||||
|
||||
expect(totalDuration).toBeLessThan(300000); // 5 minutes max
|
||||
tools.log(`Corpus performance analysis completed in ${totalDuration}ms`);
|
||||
});
|
||||
|
||||
tap.test('VAL-12: Validation Performance - Stress Testing', { timeout: testTimeout }, async (tools) => {
|
||||
const startTime = Date.now();
|
||||
|
||||
// Stress test with rapid successive validations
|
||||
const stressTestXml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
|
||||
<ID>STRESS-TEST-001</ID>
|
||||
<IssueDate>2024-01-01</IssueDate>
|
||||
<InvoiceTypeCode>380</InvoiceTypeCode>
|
||||
<DocumentCurrencyCode>EUR</DocumentCurrencyCode>
|
||||
<LegalMonetaryTotal>
|
||||
<PayableAmount currencyID="EUR">100.00</PayableAmount>
|
||||
</LegalMonetaryTotal>
|
||||
</Invoice>`;
|
||||
|
||||
const stressIterations = 200;
|
||||
const stressTimes = [];
|
||||
|
||||
try {
|
||||
for (let i = 0; i < stressIterations; i++) {
|
||||
const iterationStart = Date.now();
|
||||
|
||||
const invoice = new EInvoice();
|
||||
await invoice.fromXmlString(stressTestXml);
|
||||
await invoice.validate();
|
||||
|
||||
const iterationTime = Date.now() - iterationStart;
|
||||
stressTimes.push(iterationTime);
|
||||
|
||||
// Log progress every 50 iterations
|
||||
if ((i + 1) % 50 === 0) {
|
||||
const currentAvg = stressTimes.slice(-50).reduce((a, b) => a + b, 0) / 50;
|
||||
tools.log(`Stress test progress: ${i + 1}/${stressIterations}, avg last 50: ${currentAvg.toFixed(1)}ms`);
|
||||
}
|
||||
}
|
||||
|
||||
// Analyze stress test results
|
||||
const avgStressTime = stressTimes.reduce((a, b) => a + b, 0) / stressTimes.length;
|
||||
const minStressTime = Math.min(...stressTimes);
|
||||
const maxStressTime = Math.max(...stressTimes);
|
||||
const stdDev = Math.sqrt(stressTimes.reduce((sum, time) => sum + Math.pow(time - avgStressTime, 2), 0) / stressTimes.length);
|
||||
|
||||
// Check for performance degradation over time
|
||||
const firstHalf = stressTimes.slice(0, stressIterations / 2);
|
||||
const secondHalf = stressTimes.slice(stressIterations / 2);
|
||||
const firstHalfAvg = firstHalf.reduce((a, b) => a + b, 0) / firstHalf.length;
|
||||
const secondHalfAvg = secondHalf.reduce((a, b) => a + b, 0) / secondHalf.length;
|
||||
const degradation = ((secondHalfAvg - firstHalfAvg) / firstHalfAvg) * 100;
|
||||
|
||||
tools.log(`Stress test results (${stressIterations} iterations):`);
|
||||
tools.log(` Average time: ${avgStressTime.toFixed(1)}ms`);
|
||||
tools.log(` Min: ${minStressTime}ms, Max: ${maxStressTime}ms`);
|
||||
tools.log(` Standard deviation: ${stdDev.toFixed(1)}ms`);
|
||||
tools.log(` Performance degradation: ${degradation.toFixed(1)}%`);
|
||||
|
||||
// Performance expectations
|
||||
expect(avgStressTime).toBeLessThan(50); // 50ms average max
|
||||
expect(degradation).toBeLessThan(20); // Less than 20% degradation
|
||||
expect(stdDev).toBeLessThan(avgStressTime); // Standard deviation should be reasonable
|
||||
|
||||
} catch (error) {
|
||||
tools.log(`Stress test failed: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
|
||||
const totalDuration = Date.now() - startTime;
|
||||
PerformanceTracker.recordMetric('validation-performance-stress', totalDuration);
|
||||
|
||||
tools.log(`Stress test completed in ${totalDuration}ms`);
|
||||
});
|
||||
|
||||
tap.test('VAL-12: Performance Summary', async (tools) => {
|
||||
const operations = [
|
||||
'validation-performance-single',
|
||||
'validation-performance-concurrent',
|
||||
'validation-performance-large',
|
||||
'validation-performance-memory',
|
||||
'validation-performance-corpus',
|
||||
'validation-performance-stress'
|
||||
];
|
||||
|
||||
tools.log(`\n=== Validation Performance Summary ===`);
|
||||
|
||||
for (const operation of operations) {
|
||||
const summary = await PerformanceTracker.getSummary(operation);
|
||||
if (summary) {
|
||||
tools.log(`${operation}:`);
|
||||
tools.log(` avg=${summary.average}ms, min=${summary.min}ms, max=${summary.max}ms, p95=${summary.p95}ms`);
|
||||
}
|
||||
}
|
||||
|
||||
tools.log(`\nValidation performance testing completed successfully.`);
|
||||
});
|
Reference in New Issue
Block a user