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
1 change: 1 addition & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@ out/
### custom ###
unihub_dev.mv.db
unihub_dev.trace.db
unihub_dev.lock.db
src/main/resources/application-secret.yml
.env
3 changes: 3 additions & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ dependencies {

// AWS S3
implementation("io.awspring.cloud:spring-cloud-aws-starter-s3:3.3.0")

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


Expand Down
80 changes: 80 additions & 0 deletions backend/k6/30_student_enrollment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
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 = __ENV.BASE || "http://host.docker.internal:8080";

// 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 = {
scenarios: {
enrollmentTest: {
executor: "per-vu-iterations",
vus: VUS,
iterations: 1,
maxDuration: "30s",
},
},
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);
}
}


// 실행 방법
// 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 30_student_enrollment.js
78 changes: 78 additions & 0 deletions backend/k6/30_student_enrollmentCancel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
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 = __ENV.BASE || "http://host.docker.internal:8080";

// 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);
}
}

// 실행 방법
// 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 30_student_enrollmentCancel.js
77 changes: 77 additions & 0 deletions backend/k6/enroll-cap30-vus100.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import http from "k6/http";
import {check} from "k6";
import {SharedArray} from "k6/data";
import {Counter} from "k6/metrics";

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

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

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

export let options = {
scenarios: {
enrollmentTest: {
executor: "per-vu-iterations",
vus: VUS,
iterations: 1,
maxDuration: "30s",
},
},
thresholds: {
// 30건 2xx 성공, 70건 비2xx 실패
"enroll_success": ["count == 30"],
"enroll_fail": ["count == 70"],
},
};

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"}}
);
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);
}
}


// 실행 방법
// 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 enroll-cap30-vus100.js
74 changes: 74 additions & 0 deletions backend/k6/enroll-single-student-v5.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import http from "k6/http";
import {Counter} from "k6/metrics";

// —— 테스트 파라미터 ——
// 한 학생이 동시에 보낼 요청 수
const VUS = 5;
const ITERATIONS = 5;
const COURSE_ID = 11;
const BASE = __ENV.BASE || "http://host.docker.internal:8080";

// 테스트할 단일 학생 계정
const STUDENT = {
email: "concurrencyStudent1@auni.ac.kr",
password: "studentPw",
};

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

export let options = {
scenarios: {
singleStudentTest: {
executor: "shared-iterations",
vus: VUS, // 동시에 5 VU
iterations: ITERATIONS,// 총 5회 반복
maxDuration: "10s",
},
},
thresholds: {
// 1번만 성공, 4번은 실패를 기대
"enroll_success": ["count == 1"],
"enroll_fail": ["count == 4"],
},
};

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

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

if (enrollRes.status >= 200 && enrollRes.status < 300) {
enrollSuccess.add(1);
} else {
enrollFail.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 enroll-single-student-v5.js
Loading
Loading