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

[FEAT] 다음 라운드 넘어가기 API #75

Merged
merged 8 commits into from
Jul 26, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class BalanceContentController {

private final BalanceContentService balanceContentService;

@GetMapping("/balances/rooms/{roomId}/question")
@GetMapping("/balances/rooms/{roomId}/content")
public BalanceContentResponse getBalanceContent(@PathVariable @Positive Long roomId) {
return balanceContentService.findRecentBalanceContent(roomId);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ddangkong.controller.balance.room;

import ddangkong.controller.balance.content.dto.BalanceContentResponse;
import ddangkong.controller.balance.room.dto.RoomJoinRequest;
import ddangkong.controller.balance.room.dto.RoomJoinResponse;
import ddangkong.controller.balance.room.dto.RoomMembersResponse;
Expand All @@ -8,7 +9,6 @@
import jakarta.validation.constraints.Positive;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand All @@ -26,9 +26,14 @@ public class RoomController {

private final RoomService roomService;

@GetMapping("/balances/rooms/{roomId}/members")
public RoomMembersResponse getAllBalanceGameRoomMember(@Positive @PathVariable Long roomId) {
return roomService.findAllRoomMember(roomId);
}

@ResponseStatus(HttpStatus.CREATED)
@PostMapping("/balances/rooms")
public RoomJoinResponse creatRoom(@Valid @RequestBody RoomJoinRequest request) {
public RoomJoinResponse createRoom(@Valid @RequestBody RoomJoinRequest request) {
return roomService.createRoom(request.nickname());
}

Expand All @@ -38,10 +43,9 @@ public RoomJoinResponse joinRoom(@PathVariable @Positive Long roomId, @Valid @Re
return roomService.joinRoom(request.nickname(), roomId);
}

@GetMapping("/balances/rooms/{roomId}/members")
public ResponseEntity<RoomMembersResponse> getAllBalanceGameRoomMember(@Positive @PathVariable Long roomId) {
RoomMembersResponse response = roomService.findAllRoomMember(roomId);

return ResponseEntity.ok(response);
@ResponseStatus(HttpStatus.CREATED)
@PostMapping("/balances/rooms/{roomId}/contents")
public BalanceContentResponse moveToNextRound(@PathVariable @Positive Long roomId) {
return roomService.moveToNextRound(roomId);
}
}
17 changes: 15 additions & 2 deletions backend/src/main/java/ddangkong/domain/balance/room/Room.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ddangkong.domain.balance.room;

import ddangkong.exception.BadRequestException;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
Expand All @@ -12,7 +13,7 @@
public class Room {

private static final int DEFAULT_TOTAL_ROUND = 5;
private static final int DEFAULT_CURRENT_ROUND = 1;
private static final int START_ROUND = 1;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand All @@ -22,5 +23,17 @@ public class Room {
private int totalRound = DEFAULT_TOTAL_ROUND;

@Column(nullable = false)
private int currentRound = DEFAULT_CURRENT_ROUND;
private int currentRound = START_ROUND;

public void moveToNextRound() {
if (canMoveToNextRound()) {
currentRound++;
return;
}
throw new BadRequestException("마지막 라운드입니다.");
}

private boolean canMoveToNextRound() {
return currentRound < totalRound;
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
package ddangkong.service.balance.room;

import ddangkong.controller.balance.content.dto.BalanceContentResponse;
import ddangkong.controller.balance.member.dto.MemberResponse;
import ddangkong.controller.balance.room.dto.RoomJoinResponse;
import ddangkong.controller.balance.room.dto.RoomMemberResponse;
import ddangkong.controller.balance.room.dto.RoomMembersResponse;
import ddangkong.domain.balance.content.BalanceContent;
import ddangkong.domain.balance.option.BalanceOption;
import ddangkong.domain.balance.option.BalanceOptionRepository;
import ddangkong.domain.balance.room.Room;
import ddangkong.domain.balance.room.RoomContent;
import ddangkong.domain.balance.room.RoomContentRepository;
import ddangkong.domain.balance.room.RoomRepository;
import ddangkong.domain.member.Member;
import ddangkong.domain.member.MemberRepository;
import ddangkong.exception.BadRequestException;
import ddangkong.exception.InternalServerException;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -17,10 +25,27 @@
@RequiredArgsConstructor
public class RoomService {

private static final int BALANCE_OPTION_SIZE = 2;

private final RoomRepository roomRepository;

private final MemberRepository memberRepository;

private final RoomContentRepository roomContentRepository;

private final BalanceOptionRepository balanceOptionRepository;

@Transactional(readOnly = true)
public RoomMembersResponse findAllRoomMember(Long roomId) {
Room room = roomRepository.getById(roomId);

List<RoomMemberResponse> response = memberRepository.findAllByRoom(room)
.stream()
.map(RoomMemberResponse::new)
.toList();
return new RoomMembersResponse(response);
}

@Transactional
public RoomJoinResponse createRoom(String nickname) {
Room room = roomRepository.save(new Room());
Expand All @@ -35,14 +60,34 @@ public RoomJoinResponse joinRoom(String nickname, Long roomId) {
return new RoomJoinResponse(room.getId(), new MemberResponse(member));
}

@Transactional(readOnly = true)
public RoomMembersResponse findAllRoomMember(Long roomId) {
@Transactional
public BalanceContentResponse moveToNextRound(Long roomId) {
Room room = roomRepository.getById(roomId);
room.moveToNextRound();

List<RoomMemberResponse> response = memberRepository.findAllByRoom(room)
.stream()
.map(RoomMemberResponse::new)
.toList();
return new RoomMembersResponse(response);
RoomContent roomContent = findCurrentRoomContent(room);
List<BalanceOption> balanceOptions = findBalanceOptions(roomContent.getBalanceContent());
return BalanceContentResponse.builder()
.roomContent(roomContent)
.firstOption(balanceOptions.get(0))
.secondOption(balanceOptions.get(1))
.build();
}

private RoomContent findCurrentRoomContent(Room room) {
return roomContentRepository.findByRoomAndRound(room, room.getCurrentRound())
.orElseThrow(() -> new BadRequestException("해당 방의 현재 진행중인 질문이 존재하지 않습니다."));
}

private List<BalanceOption> findBalanceOptions(BalanceContent balanceContent) {
List<BalanceOption> balanceOptions = balanceOptionRepository.findAllByBalanceContent(balanceContent);
validateBalanceOptions(balanceOptions);
return balanceOptions;
}

private void validateBalanceOptions(List<BalanceOption> balanceOptions) {
if (balanceOptions.size() != BALANCE_OPTION_SIZE) {
throw new InternalServerException("밸런스 게임의 선택지가 %d개입니다".formatted(balanceOptions.size()));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ class 현재_방의_내용_조회 {
void 현재_방의_질문을_조회할_수_있다() {
// when
BalanceContentResponse actual = RestAssured.given().log().all()
.when().get("/api/balances/rooms/1/question")
.pathParam("roomId", 1L)
.when().get("/api/balances/rooms/{roomId}/content")
.then().log().all()
.statusCode(200)
.extract().as(BalanceContentResponse.class);
Expand All @@ -37,7 +38,8 @@ class 현재_방의_내용_조회 {
void 방의_식별자가_음수인_경우_예외를_던진다() {
// when & then
RestAssured.given().log().all()
.when().get("/api/balances/rooms/-1/question")
.pathParam("roomId", -1L)
.when().get("/api/balances/rooms/{roomId}/content")
.then().log().all()
.statusCode(400);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import static org.assertj.core.api.Assertions.assertThat;

import ddangkong.controller.BaseControllerTest;
import ddangkong.controller.balance.content.dto.BalanceContentResponse;
import ddangkong.controller.balance.option.dto.BalanceOptionResponse;
import ddangkong.controller.balance.room.dto.RoomJoinResponse;
import ddangkong.controller.balance.room.dto.RoomMembersResponse;
import ddangkong.domain.balance.content.Category;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import java.util.HashMap;
Expand All @@ -15,6 +18,23 @@

class RoomControllerTest extends BaseControllerTest {

@Nested
class 밸런스_게임_방_전체_멤버_조회 {

@Test
void 게임_방_전체_멤버_조회() {
//when
RoomMembersResponse actual = RestAssured.given()
.when().get("/api/balances/rooms/1/members")
.then().contentType(ContentType.JSON).log().all()
.statusCode(200)
.extract().as(RoomMembersResponse.class);

//then
Assertions.assertThat(actual.members()).hasSize(4);
}
}

@Nested
class 방_생성 {

Expand Down Expand Up @@ -62,8 +82,7 @@ class 방_참가 {
void 방에_참가할_수_있다() {
// given
String nickname = "참가자";
Map<String, Object> body = new HashMap<>();
body.put("nickname", nickname);
Map<String, Object> body = Map.of("nickname", nickname);

// when & then
RestAssured.given().log().all()
Expand All @@ -79,8 +98,7 @@ class 방_참가 {
void 방에_참가한_멤버는_방장이_아니다() {
// given
String nickname = "참가자";
Map<String, Object> body = new HashMap<>();
body.put("nickname", nickname);
Map<String, Object> body = Map.of("nickname", nickname);

// when & then
RoomJoinResponse actual = RestAssured.given().log().all()
Expand All @@ -92,24 +110,39 @@ class 방_참가 {
.extract().as(RoomJoinResponse.class);

assertThat(actual.member().isMaster()).isFalse();

}
}

@Nested
class 밸런스_게임_방_전체_멤버_조회 {
class 다음_라운드_진행 {

private static final BalanceContentResponse EXPECTED_RESPONSE = new BalanceContentResponse(
3L, Category.EXAMPLE, 5, 3, "다음 중 여행가고 싶은 곳은?",
new BalanceOptionResponse(5L, "산"),
new BalanceOptionResponse(6L, "바다"));

@Test
void 게임_방_전체_멤버_조회() {
//when
RoomMembersResponse actual = RestAssured.given()
.when().get("/api/balances/rooms/1/members")
.then().contentType(ContentType.JSON).log().all()
.statusCode(200)
.extract().as(RoomMembersResponse.class);
void 다음_라운드로_진행할_수_있다() {
// when
BalanceContentResponse actual = RestAssured.given().log().all()
.pathParam("roomId", 1L)
.when().post("/api/balances/rooms/{roomId}/contents")
.then().log().all()
.statusCode(201)
.extract().as(BalanceContentResponse.class);

//then
Assertions.assertThat(actual.members()).hasSize(4);
// then
assertThat(actual).isEqualTo(EXPECTED_RESPONSE);
}

@Test
void 방의_식별자가_음수인_경우_예외를_던진다() {
// when & then
RestAssured.given().log().all()
.pathParam("roomId", -1L)
.when().post("/api/balances/rooms/{roomId}/contents")
.then().log().all()
.statusCode(400);
}
}
}
50 changes: 50 additions & 0 deletions backend/src/test/java/ddangkong/domain/balance/room/RoomTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package ddangkong.domain.balance.room;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import ddangkong.exception.BadRequestException;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

class RoomTest {

@Nested
class 다음_라운드로_이동 {

private static final int START_ROUND = 1;
private static final int TOTAL_ROUND = 5;

@Test
void 다음_라운드로_이동할_수_있다() {
// given
Room room = new Room();
int currentRound = room.getCurrentRound();
int expectedRound = currentRound + 1;

// when
room.moveToNextRound();

// then
assertThat(room.getCurrentRound()).isEqualTo(expectedRound);
}

@Test
void 마지막_라운드_일_경우_예외를_던진다() {
// given
Room room = new Room();
goToFinalRound(room);

// when & then
assertThatThrownBy(() -> room.moveToNextRound())
.isInstanceOf(BadRequestException.class)
.hasMessage("마지막 라운드입니다.");
}

private void goToFinalRound(Room room) {
for (int round = START_ROUND; round < TOTAL_ROUND; round++) {
room.moveToNextRound();
}
}
}
Comment on lines +32 to +49
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

의견) 이후에 Room의 total_round를 생성자를 통해 입력하게 되면 이 테스트는 터지게될 수도 있으니 주의가 필요할 것 같네요.

Copy link
Contributor Author

@leegwichan leegwichan Jul 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아마도 지금 사용하는 생성자를 유지하지 않을까 싶어요. 결국에는 초기 방 생성시에는 TOTAL_ROUND의 기본 값이 필요할 테니까요. 그리고 updateTotalRound() 형식으로 바뀌어지지 않을까요?

미래를 생각하는 힘드니, 지금 이 형식은 유지하고, 나중에 값이 바뀔 수 있을 때 조금 다듬어야 겠네요;;

}
Loading