From 205af1535638f5410880d3156662432429f51058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EB=8C=80=ED=9D=AC?= <joedaehui@ajou.ac.kr> Date: Fri, 6 Dec 2024 10:10:31 +0900 Subject: [PATCH] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95=20(#23)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- services/performance.test.js | 273 ++++++++++++++++++++++++----------- 1 file changed, 189 insertions(+), 84 deletions(-) diff --git a/services/performance.test.js b/services/performance.test.js index 9104525..e987e86 100644 --- a/services/performance.test.js +++ b/services/performance.test.js @@ -1,98 +1,203 @@ -const axios = require('axios'); -const { performance } = require('perf_hooks'); - -async function runPerformanceTest() { - const baseURL = 'http://localhost:3000/api'; - const iterations = 100; - - // 테스트 데이터 - const testSchedule = { - title: 'Test Schedule', - is_fixed: true, - time_indices: [36, 37, 38] - }; - - console.log(`Starting performance test with ${iterations} iterations`); - - // 테스트 결과 저장용 객체 - const results = { - create: [], - update: [], - getAll: [], - getByTimeIdx: [], - delete: [] - }; - - for (let i = 0; i < iterations; i++) { +// services/performance.test.js +require('dotenv').config(); +const { Op } = require('sequelize'); +const ScheduleService = require('./scheduleService'); +const sequelize = require('../config/sequelize'); +const Schedule = require('../models/schedule'); + +class PerformanceTester { + constructor() { + this.testUserIds = [1, 2, 3, 4, 5]; // 5명의 테스트 유저만 사용 + this.results = { + operations: { + createSchedules: [], + getAllSchedules: [], + updateSchedules: [], + deleteSchedules: [] + }, + summary: {} + }; + } + + async setup() { try { - console.log(`Running iteration ${i + 1}/${iterations}`); - - // Create - const createStart = performance.now(); - await axios.post(`${baseURL}/schedule`, testSchedule); - results.create.push(performance.now() - createStart); - - // Get All Schedules - const getAllStart = performance.now(); - await axios.get(`${baseURL}/schedule/all`); - results.getAll.push(performance.now() - getAllStart); - - // Get Schedule by Time Index - const getByTimeIdxStart = performance.now(); - await axios.get(`${baseURL}/schedule/36`); - results.getByTimeIdx.push(performance.now() - getByTimeIdxStart); - - // Update - const updateStart = performance.now(); - await axios.put(`${baseURL}/schedule`, { - originalTitle: 'Test Schedule', - title: 'Updated Schedule', - is_fixed: true, - time_indices: [39, 40, 41] - }); - results.update.push(performance.now() - updateStart); - - // Delete - const deleteStart = performance.now(); - await axios.delete(`${baseURL}/schedule`, { - data: { title: 'Updated Schedule' } + await sequelize.authenticate(); + console.log('Database connection established successfully.'); + await Schedule.destroy({ where: {}, force: true }); + console.log('Test data cleaned successfully.'); + console.log('Using existing user IDs:', this.testUserIds); + } catch (error) { + console.error('Setup failed:', error); + throw error; + } + } + + async runLoadTest() { + console.log('Starting simplified test...'); + + const testSchedules = this.testUserIds.map((userId, i) => ({ + userId, + title: `Test Schedule ${i}`, + is_fixed: true, + time_indices: [i * 2, i * 2 + 1] + })); + + console.log('Test schedules:', testSchedules); + + const transaction = await sequelize.transaction(); + try { + // Create 테스트 + console.log('\nTesting createSchedules...'); + const createdSchedules = []; + for (const schedule of testSchedules) { + const result = await this.measureOperation('createSchedules', async () => { + const created = await ScheduleService.createSchedules(schedule, transaction); + console.log(`Created schedule for user ${schedule.userId}`); + return created; + }); + if (result) createdSchedules.push(result); + } + await transaction.commit(); + + // 생성된 스케줄 확인 + const verifySchedules = await Schedule.findAll({ + where: { + user_id: { [Op.in]: this.testUserIds } + }, + raw: true }); - results.delete.push(performance.now() - deleteStart); + console.log('\nVerified schedules:', verifySchedules); + + // GetAll 테스트 + console.log('\nTesting getAllSchedules...'); + for (const userId of this.testUserIds) { + await this.measureOperation('getAllSchedules', async () => { + return await ScheduleService.getAllSchedules(userId); + }); + } + + // Update 테스트 + console.log('\nTesting updateSchedules...'); + for (const schedule of createdSchedules) { + await this.measureOperation('updateSchedules', async () => { + return await ScheduleService.updateSchedules(schedule.user_id, { + originalTitle: schedule.title, + title: `Updated ${schedule.title}`, + is_fixed: schedule.is_fixed, + time_indices: schedule.time_indices + }); + }); + } + + // Delete 테스트 + console.log('\nTesting deleteSchedules...'); + const deleteTransaction = await sequelize.transaction(); + try { + for (const schedule of createdSchedules) { + await this.measureOperation('deleteSchedules', async () => { + return await ScheduleService.deleteSchedules( + schedule.user_id, + `Updated ${schedule.title}`, + deleteTransaction + ); + }); + } + await deleteTransaction.commit(); + } catch (error) { + await deleteTransaction.rollback(); + throw error; + } + } catch (error) { + await transaction.rollback(); + throw error; + } + this.analyzePerfResults(); + } + + async measureOperation(name, operation) { + const start = process.hrtime.bigint(); + try { + const result = await operation(); + const end = process.hrtime.bigint(); + const duration = Number(end - start) / 1000000; + this.results.operations[name].push({ success: true, duration }); + return result; } catch (error) { - console.error(`Iteration ${i} failed:`, error.message); + const end = process.hrtime.bigint(); + const duration = Number(end - start) / 1000000; + this.results.operations[name].push({ + success: false, + duration, + error: error.message + }); + console.error(`Error in ${name}:`, error.message); + return null; } } - // 결과 분석 - const analyzeResults = (times) => { - const avg = times.reduce((a, b) => a + b, 0) / times.length; - const min = Math.min(...times); - const max = Math.max(...times); - return { - average: avg.toFixed(2), - min: min.toFixed(2), - max: max.toFixed(2), - count: times.length - }; - }; + analyzePerfResults() { + Object.entries(this.results.operations).forEach(([operation, results]) => { + const successful = results.filter(r => r.success); + const failed = results.filter(r => !r.success); + if (successful.length > 0) { + const durations = successful.map(r => r.duration); + this.results.summary[operation] = { + totalRequests: results.length, + successCount: successful.length, + failCount: failed.length, + avgDuration: durations.reduce((a, b) => a + b, 0) / successful.length, + minDuration: Math.min(...durations), + maxDuration: Math.max(...durations), + p95: this.calculatePercentile(durations, 95), + p99: this.calculatePercentile(durations, 99) + }; + } + }); + this.printResults(); + } - // 성능 통계 출력 - console.log('\nPerformance Results (ms):'); - console.log('Create Schedule:', analyzeResults(results.create)); - console.log('Get All Schedules:', analyzeResults(results.getAll)); - console.log('Get Schedule by Time Index:', analyzeResults(results.getByTimeIdx)); - console.log('Update Schedule:', analyzeResults(results.update)); - console.log('Delete Schedule:', analyzeResults(results.delete)); + calculatePercentile(array, percentile) { + const sorted = array.sort((a, b) => a - b); + const index = Math.ceil((percentile / 100) * sorted.length) - 1; + return sorted[index]; + } + + printResults() { + console.log('\n=== Performance Test Results ==='); + Object.entries(this.results.summary).forEach(([operation, stats]) => { + console.log(`\n${operation}:`); + console.log(`Total Requests: ${stats.totalRequests}`); + console.log(`Success Rate: ${((stats.successCount / stats.totalRequests) * 100).toFixed(2)}%`); + console.log(`Average Duration: ${stats.avgDuration.toFixed(2)}ms`); + console.log(`Min Duration: ${stats.minDuration.toFixed(2)}ms`); + console.log(`Max Duration: ${stats.maxDuration.toFixed(2)}ms`); + console.log(`95th Percentile: ${stats.p95.toFixed(2)}ms`); + console.log(`99th Percentile: ${stats.p99.toFixed(2)}ms`); + }); + } + + async cleanup() { + try { + await Schedule.destroy({ where: {}, force: true }); + console.log('Cleanup completed successfully.'); + } catch (error) { + console.error('Cleanup failed:', error); + } + } +} - // 성능 통계 API 호출 +async function runTests() { + const tester = new PerformanceTester(); try { - const stats = await axios.get(`${baseURL}/performance/stats`); - console.log('\nDetailed Performance Statistics:', JSON.stringify(stats.data, null, 2)); + await tester.setup(); + console.log('Starting performance tests...'); + await tester.runLoadTest(); } catch (error) { - console.error('Failed to fetch performance stats:', error.message); + console.error('Test failed:', error); + } finally { + await sequelize.close(); } } -// 테스트 실행 -runPerformanceTest().catch(console.error); \ No newline at end of file +runTests(); \ No newline at end of file -- GitLab