Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ dependencies {

// Redisson (redis를 통한 분산락)
implementation("org.redisson:redisson-spring-boot-starter:3.46.0")

// prometheus (모니터링툴)
runtimeOnly 'io.micrometer:micrometer-registry-prometheus'

}


Expand Down
72 changes: 72 additions & 0 deletions backend/k6/cancel-cap30-vus100.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import http from "k6/http";
import {SharedArray} from "k6/data";
import {Counter} from "k6/metrics";

// —— 테스트 파라미터 ——
const VUS = 100;
const COURSE_ID = 11;
const BASE = "http://host.docker.internal:8080";

// students.json 로드 (100개 계정)
const users = new SharedArray("students", () =>
JSON.parse(open("students.json"))
);

// 성공/실패 카운터
export let cancelSuccess = new Counter("cancel_success");
export let cancelFail = new Counter("cancel_fail");
export let loginFail = new Counter("login_fail");

export let options = {
scenarios: {
cancelTest: {
executor: "per-vu-iterations",
vus: VUS,
iterations: 1,
maxDuration: "30s",
},
},
thresholds: {
// 100건 중 100건 2xx 기대
"cancel_success": ["count == 30"],
"cancel_fail": ["count == 0"],
},
};

export default function () {
// 각 VU마다 한 번씩 실행
const user = users[(__VU - 1) % users.length];

// 1) 로그인
let loginRes = http.post(
`${BASE}/api/members/login`,
JSON.stringify({email: user.email, password: user.password}),
{headers: {"Content-Type": "application/json"}}
);
if (loginRes.status !== 200) {
loginFail.add(1);
return;
}
const token = loginRes.json("data.accessToken");

// 2) 수강 취소 요청
let res = http.del(
`${BASE}/api/enrollments/${COURSE_ID}`,
null,
{
headers: {
"Authorization": `Bearer ${token}`,
},
}
);
if (res.status >= 200 && res.status < 300) {
cancelSuccess.add(1);
} else {
cancelFail.add(1);
}
}
// 실행 방법
// 1. Docker 환경에서 실행
// 2. c: 경로에 js 파일과 students.json 파일을 저장
// 3. 해당 경로로 이동하여 powershell에서 아래 명령어 실행
// docker run --rm --name k6_1 --network common -v ${pwd}:/scripts -w /scripts grafana/k6:latest run cancel-cap30-vus100.js
2 changes: 1 addition & 1 deletion backend/k6/enroll-cap30-vus100.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {Counter} from "k6/metrics";
// —— 테스트 파라미터 ——
const VUS = 100;
const COURSE_ID = 11;
const BASE = __ENV.BASE || "http://host.docker.internal:8080";
const BASE = "http://host.docker.internal:8080";

// students.json 로드 (100개 계정)
const users = new SharedArray("students", () =>
Expand Down
86 changes: 86 additions & 0 deletions backend/k6/prod/30_student_enrollment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import http from "k6/http";
import {check} from "k6";
import {SharedArray} from "k6/data";
import {Counter} from "k6/metrics";

// —— 테스트 파라미터 ——
const VUS = 30; // 30명의 학생만
const COURSE_ID = 11;
const BASE = "https://api.un1hub.site";

// students.json 로드 (100개 계정)
const allUsers = new SharedArray("students", () =>
JSON.parse(open("students.json"))
);

// 앞에서부터 30명만 사용
const users = allUsers.slice(0, VUS);

// 성공/실패 카운터
export let enrollSuccess = new Counter("enroll_success");
export let enrollFail = new Counter("enroll_fail");

export let options = {
duration: `180s`,
scenarios: {
enrollmentTest: {
executor: "per-vu-iterations",
vus: VUS,
iterations: 1,
},
},
thresholds: {
// 30명 중 30명은 성공, 0명은 실패 기대
"enroll_success": ["count == 30"],
"enroll_fail": ["count == 0"],
},
};

export default function () {
// VU 번호에 맞춰 0..29 인덱스 사용자 선택
const user = users[__VU - 1];

// 1) 로그인
let loginRes = http.post(
`${BASE}/api/members/login`,
JSON.stringify({email: user.email, password: user.password}),
{headers: {"Content-Type": "application/json"}}
);
check(loginRes, {"login 200": r => r.status === 200});
if (loginRes.status !== 200) {
enrollFail.add(1);
return;
}
const token = loginRes.json("data.accessToken");

// 2) 비동기 수강신청 요청
let res = http.post(
`${BASE}/api/enrollments`,
JSON.stringify({courseId: COURSE_ID}),
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
}
);

if (res.status >= 200 && res.status < 300) {
enrollSuccess.add(1);
} else {
enrollFail.add(1);
}
}
// cd /home/ec2-user/scripts
/**
docker run --rm \
--name k6_prometheus \
-v "$(pwd)":/scripts \
-w /scripts \
-p 6565:6565 \
-e K6_PROMETHEUS_HOST=0.0.0.0 \
-e K6_PROMETHEUS_PORT=6565 \
grafana/k6:latest run \
--out experimental-prometheus-rw=0.0.0.0:6565 \
30_student_enrollment.js
*/
86 changes: 86 additions & 0 deletions backend/k6/prod/30_student_enrollmentCancel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import http from "k6/http";
import {check} from "k6";
import {SharedArray} from "k6/data";
import {Counter} from "k6/metrics";

// —— 테스트 파라미터 ——
const VUS = 30; // 30명의 학생
const COURSE_ID = 11;
const BASE = "https://api.un1hub.site";

// students.json 로드 (100개 계정)
const allUsers = new SharedArray("students", () =>
JSON.parse(open("students.json"))
);

// 앞에서부터 30명만 사용
const users = allUsers.slice(0, VUS);

// 성공/실패 카운터
export let cancelSuccess = new Counter("cancel_success");
export let cancelFail = new Counter("cancel_fail");

export let options = {
scenarios: {
cancellationTest: {
executor: "per-vu-iterations",
vus: VUS,
iterations: 1,
maxDuration: "30s",
},
},
thresholds: {
// 30명 중 30건 성공, 0건 실패 기대
"cancel_success": ["count == 30"],
"cancel_fail": ["count == 0"],
},
};

export default function () {
// VU 번호에 맞춰 0..29 인덱스 사용자 선택
const user = users[__VU - 1];

// 1) 로그인
let loginRes = http.post(
`${BASE}/api/members/login`,
JSON.stringify({email: user.email, password: user.password}),
{headers: {"Content-Type": "application/json"}}
);
check(loginRes, {"login 200": r => r.status === 200});
if (loginRes.status !== 200) {
cancelFail.add(1);
return;
}
const token = loginRes.json("data.accessToken");

// 2) 수강 취소 요청
let res = http.del(
`${BASE}/api/enrollments/${COURSE_ID}`,
null,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);

if (res.status >= 200 && res.status < 300) {
cancelSuccess.add(1);
} else {
cancelFail.add(1);
}
}

// cd /home/ec2-user/scripts
/**
docker run --rm \
--name k6_prometheus \
-v "$(pwd)":/scripts \
-w /scripts \
-p 6565:6565 \
-e K6_PROMETHEUS_HOST=0.0.0.0 \
-e K6_PROMETHEUS_PORT=6565 \
grafana/k6:latest run \
--out experimental-prometheus-rw=0.0.0.0:6565 \
30_student_enrollmentCancel.js
*/
82 changes: 82 additions & 0 deletions backend/k6/prod/cancel-cap30-vus100.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import http from "k6/http";
import {SharedArray} from "k6/data";
import {Counter} from "k6/metrics";

// —— 테스트 파라미터 ——
const VUS = 100;
const COURSE_ID = 11;
const BASE = "https://api.un1hub.site";

// students.json 로드 (100개 계정)
const users = new SharedArray("students", () =>
JSON.parse(open("students.json"))
);

// 성공/실패 카운터
export let cancelSuccess = new Counter("cancel_success");
export let cancelFail = new Counter("cancel_fail");
export let loginFail = new Counter("login_fail");

export let options = {
scenarios: {
cancelTest: {
executor: "per-vu-iterations",
vus: VUS,
iterations: 1,
maxDuration: "30s",
},
},
thresholds: {
// 100건 중 100건 2xx 기대
"cancel_success": ["count == 30"],
"cancel_fail": ["count == 0"],
},
};

export default function () {
// 각 VU마다 한 번씩 실행
const user = users[(__VU - 1) % users.length];

// 1) 로그인
let loginRes = http.post(
`${BASE}/api/members/login`,
JSON.stringify({email: user.email, password: user.password}),
{headers: {"Content-Type": "application/json"}}
);
if (loginRes.status !== 200) {
loginFail.add(1);
return;
}
const token = loginRes.json("data.accessToken");

// 2) 수강 취소 요청
let res = http.del(
`${BASE}/api/enrollments/${COURSE_ID}`,
null,
{
headers: {
"Authorization": `Bearer ${token}`,
},
}
);
if (res.status >= 200 && res.status < 300) {
cancelSuccess.add(1);
} else {
cancelFail.add(1);
}
}

// cd /home/ec2-user/scripts
/**
docker run --rm \
--name k6_prometheus \
--network common \
-v "$(pwd)":/scripts \
-w /scripts \
-p 6565:6565 \
-e K6_PROMETHEUS_HOST=0.0.0.0 \
-e K6_PROMETHEUS_PORT=6565 \
grafana/k6:latest run \
--out experimental-prometheus-rw=0.0.0.0:6565 \
cancel-cap30-vus100.js
*/
Loading
Loading