1+ // 80%는 상세조회(GET), 20%는 좋아요 변경(POST) 요청
2+ import http from 'k6/http' ;
3+ import { sleep , check } from 'k6' ;
4+
5+ const BASE_URL = 'http://localhost:8080' ;
6+ const FEED_ID = 1 ; // 테스트할 피드 ID
7+
8+ export let options = {
9+ scenarios : {
10+ read_scenario : {
11+ executor : 'constant-vus' ,
12+ vus : 160 , // 전체 200명 중 160명은 상세 조회 전담
13+ duration : '2m' ,
14+ exec : 'readFeed' ,
15+ } ,
16+ write_scenario : {
17+ executor : 'constant-vus' ,
18+ vus : 40 , // 전체 200명 중 20명은 좋아요 변경 전담
19+ duration : '2m' ,
20+ exec : 'likeFeed' ,
21+ } ,
22+ } ,
23+ thresholds : {
24+ http_req_duration : [ 'p(95)<500' ] ,
25+ http_req_failed : [ 'rate<0.01' ] ,
26+ } ,
27+ } ;
28+
29+ // 테스트 전 사용자 별 토큰 발급
30+ export function setup ( ) {
31+ // 최대 VU 수 계산
32+ const maxVUs = 200 ;
33+ let tokens = [ ] ;
34+
35+ // 유저 ID에 대해 토큰을 미리 발급
36+ for ( let userId = 1 ; userId <= maxVUs ; userId ++ ) {
37+ const res = http . get ( `${ BASE_URL } /api/test/token/access?userId=${ userId } ` ) ;
38+ check ( res , { 'token received' : ( r ) => r . status === 200 && r . body . length > 0 } ) ;
39+ tokens . push ( res . body ) ;
40+ }
41+
42+ return { tokens} ;
43+ }
44+
45+ // 상세조회만 실행
46+ export function readFeed ( data ) {
47+ let vuIdx = __VU - 1 ;
48+ let token = data . tokens [ vuIdx ] ;
49+ let params = {
50+ headers : {
51+ 'Authorization' : `Bearer ${ token } ` ,
52+ 'Content-Type' : 'application/json' ,
53+ }
54+ } ;
55+
56+ let res = http . get ( `${ BASE_URL } /feeds/${ FEED_ID } ` , params ) ;
57+ check ( res , {
58+ 'feed detail 200' : ( r ) => r . status === 200 ,
59+ 'feed detail status 400' : ( r ) => r . status === 400 ,
60+ 'feed detail Internal server error' : ( r ) => r . status === 500 ,
61+ } ) ;
62+
63+ if ( res . status !== 200 ) {
64+ console . error ( `[VU${ __VU } ] ERROR status=${ res . status } body=${ res . body } ` ) ;
65+ }
66+
67+ sleep ( Math . random ( ) ) ; // 0~1초 내 랜덤 대기(실사용 패턴 반영)
68+ }
69+
70+ // 좋아요 변경만 실행
71+ export function likeFeed ( data ) {
72+ let vuIdx = __VU - 1 ;
73+ let token = data . tokens [ vuIdx ] ;
74+ let params = {
75+ headers : {
76+ 'Authorization' : `Bearer ${ token } ` ,
77+ 'Content-Type' : 'application/json' ,
78+ }
79+ } ;
80+
81+ // 상세 조회로 좋아요 상태 확인
82+ let getRes = http . get ( `${ BASE_URL } /feeds/${ FEED_ID } ` , params ) ;
83+ let isLiked = false ;
84+ if ( getRes . status === 200 ) {
85+ try {
86+ let body = JSON . parse ( getRes . body ) ;
87+ isLiked = body . data . isLiked ;
88+ } catch ( e ) {
89+ console . error ( `[VU${ __VU } ] 상세조회 파싱 오류:` , getRes . body ) ;
90+ }
91+ }
92+
93+ // 상태 반대로 좋아요 또는 취소 요청
94+ let payload = JSON . stringify ( { type : ! isLiked } ) ;
95+ let res = http . post ( `${ BASE_URL } /feeds/${ FEED_ID } /likes` , payload , params ) ;
96+
97+ check ( res , {
98+ 'feed like 200' : ( r ) => r . status === 200 ,
99+ 'feed like status 400' : ( r ) => r . status === 400 ,
100+ 'feed like Internal server error' : ( r ) => r . status === 500 ,
101+ } ) ;
102+
103+ if ( res . status !== 200 ) {
104+ console . error ( `[VU${ __VU } ] ERROR status=${ res . status } body=${ res . body } ` ) ;
105+ }
106+
107+ sleep ( Math . random ( ) + 0.5 ) ; // 0.5~1.5초 랜덤 대기
108+ }
109+
110+ // 테스트 결과 html 리포트로 저장
111+ import { htmlReport } from "https://raw.githubusercontent.com/benc-uk/k6-reporter/main/dist/bundle.js" ;
112+ export function handleSummary ( data ) {
113+ return {
114+ "summary.html" : htmlReport ( data ) ,
115+ } ;
116+ }
0 commit comments