Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release: 0.6.2 #235

Merged
merged 18 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ bin/

### Mac OS ###
.DS_Store

### .env ###
.env
56 changes: 56 additions & 0 deletions Docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
services:
db:
image: "mysql:8.3.0"
container_name: load_test_mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: root#1234
MYSQL_DATABASE: load_test_db
TZ: UTC

ports:
- "3000:3306"
deploy:
resources:
limits:
cpus: "0.5"
memory: "512MB"

redis:
image: "docker.io/bitnami/redis:7.2"
container_name: load_test_redis
restart: always
environment:
- ALLOW_EMPTY_PASSWORD=yes
- REDIS_AOF_ENABLED=yes
- REDIS_RDB_ENABLED=no
ports:
- "6299:6379"
deploy:
resources:
limits:
cpus: "0.5"
memory: "512MB"

teumteum-server:
build:
context: .
dockerfile: Dockerfile
restart: always
environment:
DB_URL: jdbc:mysql://db:3306/load_test_db
DB_USERNAME: root
DB_PASSWORD: root#1234
REDIS_HOST: redis
REDIS_PORT: 6379
JWT_SECERT_KEY: ${JWT_ACCESS_KEY}

depends_on:
- db
- redis
ports:
- "8080:8080"

networks:
teumteum_local:
driver: bridge
2 changes: 1 addition & 1 deletion src/gatling/java/protocol/Protocol.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class Protocol {

private static final String USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0";

public static final HttpProtocolBuilder httpProtocol = HttpDsl.http.baseUrl("https://api.teum.org")
public static final HttpProtocolBuilder httpProtocol = HttpDsl.http.baseUrl("http://localhost:8080")
.header("Content-Type", "application/json")
.userAgentHeader(USER_AGENT);

Expand Down
3 changes: 1 addition & 2 deletions src/gatling/java/simulation/SimulationSample.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ public class SimulationSample extends Simulation {
private final ScenarioBuilder scn = scenario(this.getClass().getSimpleName())
.exec(http("get user")
.get("/users/1")
.check(status().is(200))
);
.check(status().is(200)));

{
setUp(
Expand Down
66 changes: 66 additions & 0 deletions src/gatling/java/simulation/TeumTeumApiSimulation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package simulation;

import static io.gatling.javaapi.core.CoreDsl.StringBody;
import static io.gatling.javaapi.core.CoreDsl.constantUsersPerSec;
import static io.gatling.javaapi.core.CoreDsl.jsonPath;
import static io.gatling.javaapi.core.CoreDsl.rampUsersPerSec;
import static io.gatling.javaapi.core.CoreDsl.scenario;
import static io.gatling.javaapi.http.HttpDsl.http;
import static io.gatling.javaapi.http.HttpDsl.status;
import static protocol.Protocol.httpProtocol;

import io.gatling.javaapi.core.ScenarioBuilder;
import io.gatling.javaapi.core.Simulation;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import net.datafaker.Faker;

public class TeumTeumApiSimulation extends Simulation {

private static final Faker faker = new Faker();
private final ScenarioBuilder teumteumScn = scenario("TeumTeum 찬해지기 API 부하 테스트를 진행한다.")
.exec(session ->
session
.set("id", java.util.UUID.randomUUID().toString())
.set("name", faker.name().fullName()))

.exec(http("User 카드 등록 API 요청")
.post("/users")
.body(StringBody(
"{"
+ "\"id\": \"${id}\", "
+ "\"terms\": {\"service\": true, \"privatePolicy\": true}, "
+ "\"name\": \"${name}\", "
+ "\"birth\": \"20000402\", "
+ "\"characterId\": 2, "
+ "\"authenticated\": \"네이버\", "
+ "\"activityArea\": \"경기 시흥\", "
+ "\"mbti\": \"ENFP\", "
+ "\"status\": \"직장인\", "
+ "\"job\": {\"name\" : \"카카오 뱅크\", \"class\" : \"개발\", \"detailClass\" : \"BE 개발자\"}, "
+ "\"interests\": [\"네트워킹\", \"IT\", \"모여서 각자 일하기\"], "
+ "\"goal\": \"회사에서 좋은 사람들과 멋진 개발하기\""
+ "}"
))
.check(status().is(201))
.check(jsonPath("$.id").saveAs("userId"))
.check(jsonPath("$.accessToken").saveAs("accessToken"))
.check(jsonPath("$.refreshToken").saveAs("refreshToken")))

.exec(http("TeumTeum 친해지기 API 요청")
.post("/teum-teum/around")
.header("Authorization", "Bearer ${accessToken}")
.body(StringBody("{\"id\": ${userId}, \"latitude\": 37.5665, \"longitude\": 126.9780,"
+ " \"name\": \"test_name\", \"jobDetailClass\": \"test_job\", \"characterId\": 1}"))
.check(status().is(200))
);

{
setUp(
teumteumScn.injectOpen(
constantUsersPerSec(10).during(Duration.of(30, ChronoUnit.SECONDS)),
rampUsersPerSec(10).to(50).during(Duration.of(30, ChronoUnit.SECONDS))
).protocols(httpProtocol)
);
}
}
54 changes: 54 additions & 0 deletions src/gatling/java/simulation/UserApiSimulation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package simulation;

import static io.gatling.javaapi.core.CoreDsl.StringBody;
import static io.gatling.javaapi.core.CoreDsl.atOnceUsers;
import static io.gatling.javaapi.core.CoreDsl.jsonPath;
import static io.gatling.javaapi.core.CoreDsl.scenario;
import static io.gatling.javaapi.http.HttpDsl.http;
import static io.gatling.javaapi.http.HttpDsl.status;
import static protocol.Protocol.httpProtocol;

import io.gatling.javaapi.core.ScenarioBuilder;
import io.gatling.javaapi.core.Simulation;

public class UserApiSimulation extends Simulation {

private final ScenarioBuilder UserScn = scenario("User API 부하 테스트를 진행한다.")
.exec(http("User 카드 등록 API 요청")
.post("/users")
.body(StringBody(
"{\"id\": \"test_id\", "
+ "\"terms\": {\"service\": true, \"privatePolicy\": true}, "
+ "\"name\": \"홍길동\", "
+ "\"birth\": \"1990-01-01\", "
+ "\"characterId\": 1, "
+ "\"authenticated\": \"SNS\", "
+ "\"activityArea\": \"서울\", "
+ "\"mbti\": \"INTJ\", "
+ "\"status\": \"ACTIVE\", "
+ "\"job\": {\"name\": \"개발자\", \"class\": \"IT\", \"detailClass\": \"백엔드\"}, "
+ "\"interests\": [\"코딩\", \"독서\", \"운동\"], "
+ "\"goal\": \"성장하기 위해 노력하는 개발자가 되기\"}"
))
.check(status().is(201))
.check(jsonPath("$.id").saveAs("userId"))
.check(jsonPath("$.accessToken").saveAs("accessToken"))
.check(jsonPath("$.refreshToken").saveAs("refreshToken"))

).exec(http("User 정보 조회 API 요청")
.get("/users/${userId}")
.header("Authorization", "Bearer ${accessToken}")
.check(status().is(200))

).exec(http("User 리뷰 조회 API 요청")
.get("/users/${userId}")
.header("Authorization", "Bearer ${accessToken}")
.check(status().is(200)));


{
setUp(
UserScn.injectOpen(
atOnceUsers(10)).protocols(httpProtocol));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD", "TRACE"));
config.addExposedHeader("Authorization");
config.addExposedHeader("Authorization-refresh");
config.setAllowCredentials(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

public record ReviewRegisterRequest(
@Valid
@Size(min = 2, max = 5)
@Size(min = 1, max = 5)
List<UserReviewRegisterRequest> reviews
) {

Expand Down
28 changes: 21 additions & 7 deletions src/main/java/net/teumteum/user/service/UserService.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package net.teumteum.user.service;

import java.time.LocalDateTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
import net.teumteum.core.security.Authenticated;
import net.teumteum.core.security.service.JwtService;
import net.teumteum.core.security.service.RedisService;
import net.teumteum.core.security.service.SecurityService;
import net.teumteum.meeting.domain.Meeting;
import net.teumteum.meeting.domain.MeetingConnector;
import net.teumteum.user.domain.BalanceGameType;
import net.teumteum.user.domain.InterestQuestion;
Expand Down Expand Up @@ -109,7 +111,10 @@ public void logout(Long userId) {

@Transactional
public void registerReview(Long meetingId, Long currentUserId, ReviewRegisterRequest request) {
checkMeetingExistence(meetingId);
var meeting = getMeeting(meetingId);

checkMeetingIsClosed(meeting);
checkUserParticipationInMeeting(meeting, currentUserId);
checkUserNotRegisterSelfReview(request, currentUserId);

request.reviews()
Expand Down Expand Up @@ -157,12 +162,9 @@ private void checkUserExistence(Authenticated authenticated, String oauthId) {
);
}

private void checkMeetingExistence(Long meetingId) {
Assert.isTrue(meetingConnector.existById(meetingId),
() -> {
throw new IllegalArgumentException("meetingId에 해당하는 meeting을 찾을 수 없습니다. \"" + meetingId + "\"");
}
);
private Meeting getMeeting(Long meetingId) {
return meetingConnector.findById(meetingId)
.orElseThrow(() -> new IllegalArgumentException("meetingId에 해당하는 모임을 찾을 수 없습니다. \"" + meetingId + "\""));
}

private void checkUserNotRegisterSelfReview(ReviewRegisterRequest request, Long currentUserId) {
Expand All @@ -172,4 +174,16 @@ private void checkUserNotRegisterSelfReview(ReviewRegisterRequest request, Long
}
);
}

private void checkUserParticipationInMeeting(Meeting meeting, Long userId) {
if (!meeting.getParticipantUserIds().contains(userId)) {
throw new IllegalArgumentException("모임에 참여하지 않은 회원입니다.");
}
}

private void checkMeetingIsClosed(Meeting meeting) {
if (!LocalDateTime.now().isAfter(meeting.getPromiseDateTime())) {
throw new IllegalArgumentException("해당 모임은 아직 종료되지 않았습니다.");
}
}
}
5 changes: 5 additions & 0 deletions src/test/java/net/teumteum/integration/Repository.java
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ List<Meeting> saveAndGetCloseMeetingsByParticipantUserId(int size, Long particip
return meetingRepository.saveAllAndFlush(meetings);
}

Meeting saveAndGetCloseMeetingByParticipantUserIds(List<Long> participantUserIds) {
var meeting = MeetingFixture.getCloseMeetingWithParticipantIds(participantUserIds);
return meetingRepository.save(meeting);
}

List<Meeting> saveAndGetOpenMeetings(int size) {
var meetings = Stream.generate(MeetingFixture::getOpenMeeting)
.limit(size)
Expand Down
Loading
Loading