[Chore/performance test] - 성능 테스트 스크립트 추가#105
Conversation
WalkthroughA comprehensive performance testing suite using k6 and TypeScript was introduced under a new Changes
Sequence Diagram(s)sequenceDiagram
participant TestScript
participant Setup
participant Auth
participant ApiClient
participant API
TestScript->>Setup: Generate user IDs
Setup->>Auth: setupUsers(userIds)
Auth->>API: POST /test-login
API-->>Auth: {accessToken, refreshToken}
Auth-->>Setup: tokens[]
Setup-->>TestScript: tokens[]
loop For each scenario iteration
TestScript->>ApiClient: get/patch(endpoint, token, params)
ApiClient->>API: HTTP Request with accessToken
alt 401 Unauthorized
ApiClient->>Auth: refreshAccessToken(refreshToken)
Auth->>API: POST /token/refresh
API-->>Auth: new accessToken
Auth-->>ApiClient: new accessToken
ApiClient->>API: Retry HTTP Request with new accessToken
end
API-->>ApiClient: Response
ApiClient-->>TestScript: {response, success, newToken?}
end
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 17
🧹 Nitpick comments (6)
performance/src/config/environment.ts (1)
1-17: Add validation for parsed environment variables.The configuration structure is well-organized, but consider adding validation to prevent issues from invalid environment variable values.
Apply this diff to add basic validation:
export const config = { baseUrl: __ENV.API_BASE_URL || 'http://localhost:8080/api/v1', - maxUsers: parseInt(__ENV.MAX_USERS || '1'), + maxUsers: Math.max(1, parseInt(__ENV.MAX_USERS || '1') || 1), testDuration: __ENV.TEST_DURATION || '2m', // Thresholds - httpReqDurationP95: parseInt(__ENV.HTTP_REQ_DURATION_P95 || '1000'), - httpReqFailedRate: parseFloat(__ENV.HTTP_REQ_FAILED_RATE || '0.01'), + httpReqDurationP95: Math.max(100, parseInt(__ENV.HTTP_REQ_DURATION_P95 || '1000') || 1000), + httpReqFailedRate: Math.min(1.0, Math.max(0, parseFloat(__ENV.HTTP_REQ_FAILED_RATE || '0.01') || 0.01)), // Report settings enableHtmlReport: (__ENV.ENABLE_HTML_REPORT || 'true') === 'true', };This ensures parsed values have sensible bounds and handles NaN cases gracefully.
performance/src/tests/basic-load.ts (1)
45-55: Enhance error handling in summary formatting.The template string could fail if metrics are undefined or have unexpected structure. Add null checks for robustness.
const textSummary = ` ========== API 성능 측정 결과 ========== - 총 요청 수: ${data.metrics.http_reqs?.values.count || 0} - 총 실패 수: ${data.metrics.http_req_failed?.values.count || 0} - 평균 응답 시간: ${data.metrics.http_req_duration?.values.avg?.toFixed(2) || 0} ms - 최대 응답 시간: ${data.metrics.http_req_duration?.values.max?.toFixed(2) || 0} ms - p95 응답 시간: ${data.metrics.http_req_duration?.values['p(95)']?.toFixed(2) || 0} ms ================================== `;performance/src/tests/multi-scenario.ts (2)
52-55: Remove magic number in teardown function.The hardcoded duration value (120 seconds) should be calculated from the actual test duration or configuration.
export function teardown() { - const totalDurationInSeconds = 120; // 2분 + const totalDurationInSeconds = parseInt(config.testDuration.replace(/[^0-9]/g, '')) * 60; // Parse duration from config console.log(`\n---\n📊 다중 시나리오 테스트 완료\n---`); }
38-40: Consider adding documentation for the empty default function.The empty default function might confuse developers. Add a comment explaining why it's intentionally empty.
export default function(data: TestSetupData) { - // 기본 함수는 비워둠 (시나리오별 exec 함수 사용) + // Intentionally empty - this test uses scenario-specific exec functions (normal, mypage) + // The actual test logic is implemented in the individual scenario functions below }performance/src/scenarios/user-profile.ts (1)
31-31: Consider the impact of probabilistic execution on load testing.The random probability checks (
Math.random() > probability) make the load pattern unpredictable. This could complicate performance analysis as the actual request volume will vary between test runs.Consider using deterministic patterns or documenting this behavior clearly for test result interpretation.
Also applies to: 56-56
performance/src/scenarios/real-user-patterns.ts (1)
17-26: Remove unused variable.The
sessionStartvariable is declared but never used in thelightBrowsingmethod.lightBrowsing(tokens: UserToken[]): void { - const sessionStart = Date.now(); this.userScenarios.checkMyPage(tokens); sleep(randomFloatBetween(2, 5)); this.recordsScenarios.simpleRecordsQuery(tokens); sleep(randomFloatBetween(1, 3)); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
.gitignore(1 hunks)performance/.gitignore(1 hunks)performance/200vu-simulation.js(1 hunks)performance/README.md(1 hunks)performance/package.json(1 hunks)performance/src/config/environment.ts(1 hunks)performance/src/lib/api-client.ts(1 hunks)performance/src/lib/auth.ts(1 hunks)performance/src/lib/types.ts(1 hunks)performance/src/lib/utils.ts(1 hunks)performance/src/scenarios/real-user-patterns.ts(1 hunks)performance/src/scenarios/records-browsing.ts(1 hunks)performance/src/scenarios/user-profile.ts(1 hunks)performance/src/tests/basic-load.ts(1 hunks)performance/src/tests/multi-scenario.ts(1 hunks)performance/src/tests/real-user-simulation.ts(1 hunks)performance/src/tests/simple-iteration.ts(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (8)
performance/src/tests/simple-iteration.ts (5)
performance/src/config/environment.ts (1)
config(1-12)performance/src/lib/types.ts (1)
TestSetupData(7-9)performance/src/lib/utils.ts (1)
generateUserIds(19-21)performance/src/lib/auth.ts (1)
setupUsers(6-35)performance/src/scenarios/records-browsing.ts (1)
RecordsBrowsingScenarios(6-122)
performance/src/lib/utils.ts (1)
performance/200vu-simulation.js (3)
date(181-181)i(9-9)queryString(117-117)
performance/src/tests/basic-load.ts (5)
performance/src/lib/types.ts (1)
TestSetupData(7-9)performance/src/lib/utils.ts (1)
generateUserIds(19-21)performance/src/config/environment.ts (1)
config(1-12)performance/src/lib/auth.ts (1)
setupUsers(6-35)performance/src/scenarios/records-browsing.ts (1)
RecordsBrowsingScenarios(6-122)
performance/src/lib/auth.ts (3)
performance/src/lib/types.ts (1)
UserToken(1-5)performance/200vu-simulation.js (2)
tokens(15-15)success(53-55)performance/src/config/environment.ts (1)
config(1-12)
performance/src/tests/multi-scenario.ts (6)
performance/src/lib/types.ts (1)
TestSetupData(7-9)performance/src/lib/utils.ts (1)
generateUserIds(19-21)performance/src/config/environment.ts (1)
config(1-12)performance/src/lib/auth.ts (1)
setupUsers(6-35)performance/src/scenarios/user-profile.ts (1)
UserProfileScenarios(6-78)performance/src/scenarios/records-browsing.ts (1)
RecordsBrowsingScenarios(6-122)
performance/src/scenarios/real-user-patterns.ts (4)
performance/src/scenarios/records-browsing.ts (1)
RecordsBrowsingScenarios(6-122)performance/src/scenarios/user-profile.ts (1)
UserProfileScenarios(6-78)performance/src/lib/types.ts (1)
UserToken(1-5)performance/src/lib/utils.ts (2)
randomFloatBetween(5-7)randomIntBetween(1-3)
performance/src/lib/api-client.ts (4)
performance/src/config/environment.ts (1)
config(1-12)performance/src/lib/types.ts (3)
UserToken(1-5)QueryParams(11-16)RequestResult(24-28)performance/src/lib/utils.ts (1)
buildQueryString(23-30)performance/src/lib/auth.ts (1)
refreshAccessToken(37-60)
performance/200vu-simulation.js (3)
performance/src/tests/multi-scenario.ts (5)
options(9-30)setup(32-36)mypage(42-45)normal(47-50)teardown(52-55)performance/src/lib/auth.ts (1)
refreshAccessToken(37-60)performance/src/lib/utils.ts (3)
randomIntBetween(1-3)getRandomDateInPast(13-17)formatDate(9-11)
🪛 Biome (1.9.4)
performance/200vu-simulation.js
[error] 49-49: expected , but instead found ;
Remove ;
(parse)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Build and analyze
🔇 Additional comments (19)
.gitignore (1)
41-52: LGTM! Comprehensive performance testing exclusions.The gitignore additions properly exclude performance testing artifacts while maintaining good organization with directory-specific patterns. The inclusion of both specific performance directory patterns and a general
logs/exclusion covers the expected build outputs, dependencies, environment files, and reports.performance/.gitignore (1)
1-71: Excellent comprehensive gitignore configuration.This gitignore file provides thorough coverage of all typical artifacts for a Node.js/TypeScript performance testing project. The organization with clear section comments and the inclusion of both common and k6-specific patterns demonstrates good attention to detail. The exception for
.vscode/extensions.jsonis a nice touch for team development consistency.performance/src/lib/utils.ts (1)
1-30: Well-implemented utility functions with proper edge case handling.The utility functions are correctly implemented with good attention to detail:
- Random number generators use proper inclusive/exclusive bounds
- Date formatting produces standard ISO date format (YYYY-MM-DD)
- Query string builder properly filters null/undefined values and URL-encodes parameters
- User ID generation creates clean sequential arrays
These utilities provide a solid foundation for the performance testing framework.
performance/src/lib/types.ts (1)
1-28: Well-structured interfaces for performance testing framework.The type definitions provide a clean abstraction layer for authentication, API communication, and test data management. The interfaces are appropriately designed for their use cases:
UserTokencovers standard JWT authentication flowQueryParamsprovides flexible API query parameter typingApiResponsewith ajson()method suggests smart response parsing capabilitiesRequestResultelegantly handles authentication token refresh scenariosThe use of
anyfor the response body maintains flexibility while other fields remain strongly typed.performance/src/lib/auth.ts (2)
6-35: LGTM: Well-structured authentication setup function.The
setupUsersfunction properly handles user authentication with appropriate error handling and logging. The implementation correctly:
- Validates successful login responses using k6's
checkfunction- Handles failed logins gracefully with error logging
- Returns structured token data matching the
UserTokeninterface
37-60: LGTM: Robust token refresh implementation.The
refreshAccessTokenfunction implements proper token refresh logic with:
- Correct HTTP headers including both Content-Type and Authorization
- Response validation using k6's
checkfunction- Proper error handling and logging
- Tags for request categorization
performance/README.md (1)
1-60: LGTM: Comprehensive and well-structured documentation.The README provides clear, step-by-step instructions for:
- Installation and setup
- Environment configuration
- Building and running tests
- Development workflow
- Extending the test suite
The Korean documentation is well-organized and covers all necessary aspects for team members to effectively use the performance testing framework.
performance/src/tests/simple-iteration.ts (1)
8-18: LGTM: Well-configured simple iteration test.The test options are properly configured with:
- Single VU for controlled testing
- Reasonable iteration count (100)
- Environment-based duration configuration
- Proper threshold integration
performance/src/lib/api-client.ts (3)
7-12: LGTM: Clean constructor implementation.The constructor properly defaults to the configured base URL and maintains good separation of concerns.
14-43: Potential concurrency issue with token mutation.The
getmethod directly mutates the token array through reference (tokens[vuIndex].accessToken = result.newToken). In k6's concurrent execution model, this could lead to race conditions where multiple virtual users modify the same token simultaneously.Consider using a thread-safe token management approach or document this limitation clearly.
// Add a comment to clarify the intended usage + // Note: Token updates are not thread-safe. Use with caution in high-concurrency scenarios. if (result.newToken) { tokens[vuIndex].accessToken = result.newToken; }Likely an incorrect or invalid review comment.
68-68: Confirm 409 Conflict handling in PATCH callsWe’ve verified that in
performance/src/lib/api-client.ts, thepatchwrapper marks a 409 response as success on lines 68 and 76. Please ensure this aligns with your API’s contract:• performance/src/lib/api-client.ts:68
• performance/src/lib/api-client.ts:76Verify against your API specification that a 409 Conflict on PATCH should be treated as a successful or idempotent outcome. If only specific endpoints may legitimately return 409, consider restricting this logic to those cases.
performance/src/scenarios/user-profile.ts (2)
6-11: LGTM: Clean constructor and class structure.The class follows good composition patterns by using the ApiClient for HTTP operations.
30-52: Verify theeggIdmapping against the API designThe assumption that
eggIdis the same asuser.user_idcouldn’t be confirmed in the codebase. Please ensure this mapping matches the API’s specification or adjust accordingly.
- File:
performance/src/scenarios/user-profile.ts- Method:
updateEgg(lines 30–52)performance/src/scenarios/real-user-patterns.ts (2)
7-14: Excellent use of composition pattern.The class effectively composes
RecordsBrowsingScenariosandUserProfileScenariosto create realistic user behavior patterns. This promotes code reuse and maintainability.
16-58: Well-designed user behavior modeling.The different session methods (
lightBrowsing,browsing_session,activeUserSession,heavyUserSession) effectively model varying user activity levels with appropriate randomization and realistic delays.performance/src/tests/real-user-simulation.ts (2)
8-12: Well-configured performance thresholds.The thresholds are appropriately set for a performance test - 5% failure rate and reasonable response time percentiles (95th < 2s, 99th < 5s) provide good baseline expectations.
14-70: Excellent scenario design for realistic daily traffic simulation.The scenarios effectively model real-world usage patterns:
- Morning rush with ramping arrival rate
- Lunch time constant load
- Evening peak with highest load
- Night time low load
The executor types and parameters are well-chosen for each time period.
performance/src/scenarios/records-browsing.ts (2)
6-11: Good class structure and API client integration.The constructor properly initializes the API client, and the class encapsulates browsing scenarios well.
36-41: Excellent token management implementation.The token refresh logic properly updates the tokens array when a new token is returned, ensuring other VUs can benefit from the refreshed token.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
performance/src/scenarios/records-browsing.ts (2)
13-31: Fix inconsistent indentation in the helper method.The
generateQueryParamsmethod has inconsistent indentation that affects code readability.private generateQueryParams(maxDaysBack: number = 30): QueryParams { - - const params: QueryParams = { - page: randomIntBetween(0, 5), - size: randomIntBetween(1, 20), - }; - - let startDate = getRandomDateInPast(maxDaysBack); - let endDate = getRandomDateInPast(maxDaysBack); - - if (startDate > endDate) { - [startDate, endDate] = [endDate, startDate]; - } - - params.startDate = formatDate(startDate); - params.endDate = formatDate(endDate); - - return params; + const params: QueryParams = { + page: randomIntBetween(0, 5), + size: randomIntBetween(1, 20), + }; + + let startDate = getRandomDateInPast(maxDaysBack); + let endDate = getRandomDateInPast(maxDaysBack); + + if (startDate > endDate) { + [startDate, endDate] = [endDate, startDate]; + } + + params.startDate = formatDate(startDate); + params.endDate = formatDate(endDate); + + return params; }
85-89: Optimize parameter generation to avoid unnecessary random page generation.The method generates a random page number via
generateQueryParams()but immediately overwrites it with the loop indexi. This is inefficient and potentially confusing.Consider one of these approaches:
Option 1: Add parameters to the helper method
- const params = this.generateQueryParams(60); - params.page = i; - params.size = randomIntBetween(5, 20); + const params = this.generateQueryParams(60, i, randomIntBetween(5, 20));Option 2: Generate parameters directly for this specific use case
- const params = this.generateQueryParams(60); - params.page = i; - params.size = randomIntBetween(5, 20); + const params: QueryParams = { + page: i, + size: randomIntBetween(5, 20), + }; + + let startDate = getRandomDateInPast(60); + let endDate = getRandomDateInPast(60); + + if (startDate > endDate) { + [startDate, endDate] = [endDate, startDate]; + } + + params.startDate = formatDate(startDate); + params.endDate = formatDate(endDate);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
performance/src/scenarios/records-browsing.ts(1 hunks)performance/src/tests/basic-load.ts(1 hunks)performance/src/tests/real-user-simulation.ts(1 hunks)performance/src/tests/simple-iteration.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- performance/src/tests/simple-iteration.ts
- performance/src/tests/basic-load.ts
- performance/src/tests/real-user-simulation.ts
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ekgns33
PR: Run-Us/Runimo#105
File: performance/package.json:13-13
Timestamp: 2025-06-30T04:22:51.529Z
Learning: In the performance testing directory of the Run-Us/Runimo repository, the file `200vu-simulation.js` is legacy JavaScript code kept for reference purposes only and should not be integrated into the npm scripts or main test suite. The project uses TypeScript-based K6 performance tests as the active testing approach.
performance/src/scenarios/records-browsing.ts (1)
Learnt from: ekgns33
PR: Run-Us/Runimo#105
File: performance/package.json:13-13
Timestamp: 2025-06-30T04:22:51.529Z
Learning: In the performance testing directory of the Run-Us/Runimo repository, the file `200vu-simulation.js` is legacy JavaScript code kept for reference purposes only and should not be integrated into the npm scripts or main test suite. The project uses TypeScript-based K6 performance tests as the active testing approach.
🧬 Code Graph Analysis (1)
performance/src/scenarios/records-browsing.ts (4)
performance/src/lib/api-client.ts (1)
ApiClient(7-79)performance/src/lib/types.ts (2)
QueryParams(11-16)UserToken(1-5)performance/src/lib/utils.ts (4)
randomIntBetween(1-3)getRandomDateInPast(13-17)formatDate(9-11)randomFloatBetween(5-7)performance/200vu-simulation.js (6)
startDate(108-108)endDate(109-109)tokens(15-15)vuIndex(79-79)vuIndex(104-104)i(9-9)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Build and analyze
🔇 Additional comments (2)
performance/src/scenarios/records-browsing.ts (2)
34-58: Well-implemented scenario method with proper error handling.The
basicRecordsQuerymethod correctly uses the extracted helper method and includes appropriate error logging and token management.
61-78: Scenario method correctly implements intended design differences.The
simpleRecordsQuerymethod properly uses the helper method and maintains the intentional differences (fixed sleep timing and no error logging) for this specific test scenario.
|
jeeheaG
left a comment
There was a problem hiding this comment.
우와 타입스크립트다.. 분리 고생하셨습니다..!



작업 내역
Summary by CodeRabbit
New Features
Chores