Files
lcbp3/backend/tests/performance/approval-matrix.perf-spec.ts
T
admin 1a162bf320
CI / CD Pipeline / build (push) Successful in 4m54s
CI / CD Pipeline / deploy (push) Failing after 12m9s
feat(rfa-ai): Complete RFA Approval Refactor and AI Model Revision
2026-05-16 10:59:53 +07:00

109 lines
3.7 KiB
TypeScript

// File: backend/tests/performance/approval-matrix.perf-spec.ts
// Change Log:
// - 2026-05-16: Performance test for Approval Matrix Service with 1000+ rules
import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ResponseCodeService } from '../../src/modules/response-code/response-code.service';
import { ResponseCode } from '../../src/modules/response-code/entities/response-code.entity';
import { ResponseCodeRule } from '../../src/modules/response-code/entities/response-code-rule.entity';
import { ResponseCodeCategory } from '../../src/modules/common/enums/review.enums';
describe('ApprovalMatrixService Performance', () => {
let service: ResponseCodeService;
let responseCodeRepo: Repository<ResponseCode>;
let responseCodeRuleRepo: Repository<ResponseCodeRule>;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
ResponseCodeService,
{
provide: getRepositoryToken(ResponseCode),
useClass: Repository,
},
{
provide: getRepositoryToken(ResponseCodeRule),
useClass: Repository,
},
],
}).compile();
service = module.get<ResponseCodeService>(ResponseCodeService);
responseCodeRepo = module.get<Repository<ResponseCode>>(
getRepositoryToken(ResponseCode)
);
responseCodeRuleRepo = module.get<Repository<ResponseCodeRule>>(
getRepositoryToken(ResponseCodeRule)
);
});
it('should lookup 1000+ response code rules within 100ms', async () => {
// Arrange: Create 1000+ mock response code rules
const mockRules: Partial<ResponseCodeRule>[] = Array.from(
{ length: 1000 },
(_, i) => ({
id: i + 1,
responseCodeId: (i % 10) + 1,
documentTypeId: (i % 5) + 1,
isRequired: i % 3 === 0,
priority: (i % 5) + 1,
})
);
jest
.spyOn(responseCodeRepo, 'find')
.mockResolvedValue(mockRules as ResponseCodeRule[]);
jest.spyOn(responseCodeRuleRepo, 'find').mockResolvedValue([]);
// Act: Measure lookup time
const startTime = Date.now();
const _result = await service.findByDocumentType(1, 'SHOP_DRAWING');
const endTime = Date.now();
// Assert: Must complete within 100ms
const queryTime = endTime - startTime;
expect(queryTime).toBeLessThan(100);
// Log performance metric
process.stdout.write(
`Lookup ${mockRules.length} rules: ${queryTime}ms (target: <100ms)\n`
);
});
it('should handle concurrent lookups efficiently', async () => {
// Arrange: Mock dataset
const mockCodes: Partial<ResponseCode>[] = Array.from(
{ length: 50 },
(_, i): Partial<ResponseCode> => ({
id: i + 1,
code: `CODE-${i}`,
category: (
['ENGINEERING', 'CONTRACT', 'QUALITY'] as ResponseCodeCategory[]
)[i % 3],
description: `Description for code ${i}`,
})
);
jest
.spyOn(responseCodeRepo, 'find')
.mockResolvedValue(mockCodes as ResponseCode[]);
jest.spyOn(responseCodeRuleRepo, 'find').mockResolvedValue([]);
// Act: Run 10 concurrent lookups
const startTime = Date.now();
const promises = Array.from({ length: 10 }, () =>
service.findByDocumentType(1, 'SHOP_DRAWING')
);
await Promise.all(promises);
const endTime = Date.now();
// Assert: Total time should still be reasonable
const totalTime = endTime - startTime;
expect(totalTime).toBeLessThan(500); // Log performance metric
process.stdout.write(
`Concurrent lookups (50 codes): ${totalTime}ms (target: <500ms)\n`
);
});
});