pricelees 06f7faf7f9 [#66] 결제 & 예약 확정 로직 수정 (#67)
<!-- 제목 양식 -->
<!-- [이슈번호] 작업 요약 (예시: [#10] Gitea 템플릿 생성) -->

## 📝 관련 이슈 및 PR

**PR과 관련된 이슈 번호**
- #66

##  작업 내용
<!-- 어떤 작업을 했는지 알려주세요! -->
- 이전 #64 의 작업 이후, 결제 & 예약 확정 API 로직은 총 3개의 독립된 트랜잭션을 사용함.
- 검증 & 배치 충돌 방지를 위한 첫 번째 트랜잭션 이외의 다른 트랜잭션은 불필요하다고 판단함. -> PG사 성공 응답이 오면 나머지 작업은 \@Async 처리 후 바로 성공 응답

## 🧪 테스트
<!-- 어떤 테스트를 생각했고 진행했는지 알려주세요! -->
- 변경된 로직에 대한 통합 테스트 완료
- 성능 테스트 결과 P95 응답 시간 327.01ms -> 235.52ms / 평균 응답 시간 77.85 -> 68.16ms /  최대 응답 시간 5.26 -> 4.08초 단축

## 📚 참고 자료 및 기타
<!-- 참고한 자료, 또는 논의할 사항이 있다면 알려주세요! -->

Reviewed-on: #67
Co-authored-by: pricelees <priceelees@gmail.com>
Co-committed-by: pricelees <priceelees@gmail.com>
2025-10-17 04:59:12 +00:00

92 lines
2.5 KiB
JavaScript

import http from 'k6/http';
export const BASE_URL = __ENV.BASE_URL || 'http://localhost:8080';
export function generateRandomBase64String(length) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
let result = '';
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
export function parseIdToString(response) {
try {
const safeJsonString = response.body.replace(/"(\w*Id|id)"\s*:\s*(\d{16,})/g, '"$1":"$2"');
return JSON.parse(safeJsonString);
} catch (e) {
console.error(`JSON parsing failed for VU ${__VU}: ${e}`);
return null;
}
}
export function maxIterations() {
const maxIterationsRes = http.get(`http://localhost:8080/tests/max-iterations`)
if (maxIterationsRes.status !== 200) {
throw new Error('max-iterations 조회 실패')
}
return maxIterationsRes.json('count')
}
export function fetchUsers() {
const userCount = Math.round(maxIterations() * 0.5)
const userAccountRes = http.get(`http://localhost:8080/tests/users?count=${userCount}`)
if (userAccountRes.status !== 200) {
throw new Error('users 조회 실패')
}
return userAccountRes.json('results')
}
export function fetchStores() {
const storeIdListRes = http.get(`http://localhost:8080/tests/stores`)
if (storeIdListRes.status !== 200) {
throw new Error('stores 조회 실패')
}
return parseIdToString(storeIdListRes).results
}
export function login(account, password, principalType) {
const loginPayload = JSON.stringify({
account: account,
password: password,
principalType: principalType
})
const params = { headers: { 'Content-Type': 'application/json' }, tags: { name: '/auth/login' } }
const loginRes = http.post(`${BASE_URL}/auth/login`, loginPayload, params)
if (loginRes.status !== 200) {
throw new Error(`로그인 실패: ${__VU}`)
}
const body = parseIdToString(loginRes).data
if (principalType === 'ADMIN') {
return {
storeId: body.storeId,
accessToken: body.accessToken
}
} else {
return {
accessToken: body.accessToken
}
}
}
export function getHeaders(token, endpoint) {
const headers = {
'Content-Type': 'application/json',
};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
return { headers: headers, tags: { name: endpoint } };
}