diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java new file mode 100644 index 000000000..d583967a0 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -0,0 +1,80 @@ +package server.haengdong.application; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.Action; +import server.haengdong.domain.MemberAction; +import server.haengdong.domain.MemberActionStatus; +import server.haengdong.domain.MemberGroupIdProvider; + +@RequiredArgsConstructor +@Component +public class MemberActionFactory { + + private final MemberGroupIdProvider memberGroupIdProvider; + + public List createMemberActions( + MemberActionsSaveAppRequest request, + List memberActions, + Action action + ) { + validateMemberNames(request); + validateActions(request, memberActions); + + Long memberGroupId = memberGroupIdProvider.createGroupId(); + List createdMemberActions = new ArrayList<>(); + List actions = request.actions(); + for (MemberActionSaveAppRequest appRequest : actions) { + MemberAction memberAction = appRequest.toMemberAction(action, memberGroupId); + createdMemberActions.add(memberAction); + action = action.next(); + } + + return createdMemberActions; + } + + private void validateMemberNames(MemberActionsSaveAppRequest request) { + List memberNames = request.actions().stream() + .map(MemberActionSaveAppRequest::name) + .toList(); + + long uniqueCount = memberNames.stream().distinct().count(); + if (uniqueCount != memberNames.size()) { + throw new IllegalArgumentException(); + } + } + + private void validateActions(MemberActionsSaveAppRequest request, List memberActions) { + List reverseSortedMemberActions = memberActions.stream() + .sorted(Comparator.comparing(MemberAction::getSequence).reversed()) + .toList(); + + for (MemberActionSaveAppRequest action : request.actions()) { + validateAction(action, reverseSortedMemberActions); + } + } + + private void validateAction(MemberActionSaveAppRequest request, List memberActions) { + MemberActionStatus memberActionStatus = MemberActionStatus.of(request.status()); + if (isInvalidStatus(memberActions, request.name(), memberActionStatus)) { + throw new IllegalArgumentException(); + } + } + + private boolean isInvalidStatus( + List memberActions, + String memberName, + MemberActionStatus memberActionStatus + ) { + return memberActions.stream() + .filter(action -> action.isSameName(memberName)) + .findFirst() + .map(action -> action.isSameStatus(memberActionStatus)) + .orElse(MemberActionStatus.IN != memberActionStatus); + } +} diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java new file mode 100644 index 000000000..491981b06 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -0,0 +1,41 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.Action; +import server.haengdong.domain.Event; +import server.haengdong.domain.MemberAction; +import server.haengdong.persistence.ActionRepository; +import server.haengdong.persistence.EventRepository; +import server.haengdong.persistence.MemberActionRepository; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class MemberActionService { + + private final MemberActionFactory memberActionFactory; + private final MemberActionRepository memberActionRepository; + private final EventRepository eventRepository; + private final ActionRepository actionRepository; + + @Transactional + public void saveMemberAction(String token, MemberActionsSaveAppRequest request) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new IllegalArgumentException("event not found")); + + List findMemberActions = memberActionRepository.findAllByEvent(event); + Action action = createStartAction(event); + List memberActions = memberActionFactory.createMemberActions(request, findMemberActions, action); + memberActionRepository.saveAll(memberActions); + } + + private Action createStartAction(Event event) { + return actionRepository.findLastByEvent(event) + .map(Action::next) + .orElse(Action.createFirst(event)); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java new file mode 100644 index 000000000..a7c90efe4 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java @@ -0,0 +1,12 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.Action; +import server.haengdong.domain.MemberAction; +import server.haengdong.domain.MemberActionStatus; + +public record MemberActionSaveAppRequest(String name, String status) { + + public MemberAction toMemberAction(Action action, Long memberGroupId) { + return new MemberAction(action, name, MemberActionStatus.of(status), memberGroupId); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java new file mode 100644 index 000000000..650b908df --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java @@ -0,0 +1,6 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record MemberActionsSaveAppRequest(List actions) { +} diff --git a/server/src/main/java/server/haengdong/domain/EventStep.java b/server/src/main/java/server/haengdong/domain/EventStep.java index 741dcaba5..b25035fa5 100644 --- a/server/src/main/java/server/haengdong/domain/EventStep.java +++ b/server/src/main/java/server/haengdong/domain/EventStep.java @@ -21,7 +21,7 @@ public class EventStep { @ManyToOne(fetch = FetchType.LAZY) private Event event; - + private String name; private Long sequence; diff --git a/server/src/main/java/server/haengdong/domain/MemberAction.java b/server/src/main/java/server/haengdong/domain/MemberAction.java index 6d8ea9b20..eb8d8fdec 100644 --- a/server/src/main/java/server/haengdong/domain/MemberAction.java +++ b/server/src/main/java/server/haengdong/domain/MemberAction.java @@ -1,5 +1,6 @@ package server.haengdong.domain; +import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; @@ -21,7 +22,7 @@ public class MemberAction { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne(fetch = FetchType.LAZY) + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) private Action action; private String memberName; @@ -30,4 +31,23 @@ public class MemberAction { private MemberActionStatus status; private Long memberGroupId; + + public MemberAction(Action action, String memberName, MemberActionStatus status, Long memberGroupId) { + this.action = action; + this.memberName = memberName; + this.status = status; + this.memberGroupId = memberGroupId; + } + + public boolean isSameName(String name) { + return memberName.equals(name); + } + + public boolean isSameStatus(MemberActionStatus memberActionStatus) { + return status == memberActionStatus; + } + + public Long getSequence() { + return action.getSequence(); + } } diff --git a/server/src/main/java/server/haengdong/domain/MemberActionStatus.java b/server/src/main/java/server/haengdong/domain/MemberActionStatus.java index af7fad121..6172bdb4d 100644 --- a/server/src/main/java/server/haengdong/domain/MemberActionStatus.java +++ b/server/src/main/java/server/haengdong/domain/MemberActionStatus.java @@ -1,7 +1,16 @@ package server.haengdong.domain; +import java.util.Arrays; + public enum MemberActionStatus { IN, OUT, ; + + public static MemberActionStatus of(String status) { + return Arrays.stream(MemberActionStatus.values()) + .filter(s -> s.name().equals(status)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Invalid status: " + status)); + } } diff --git a/server/src/main/java/server/haengdong/domain/MemberGroupIdProvider.java b/server/src/main/java/server/haengdong/domain/MemberGroupIdProvider.java new file mode 100644 index 000000000..c4166e2be --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/MemberGroupIdProvider.java @@ -0,0 +1,11 @@ +package server.haengdong.domain; + +import org.springframework.stereotype.Component; + +@Component +public class MemberGroupIdProvider { + + public Long createGroupId() { + return System.currentTimeMillis(); + } +} diff --git a/server/src/main/java/server/haengdong/persistence/ActionRepository.java b/server/src/main/java/server/haengdong/persistence/ActionRepository.java index 72c573d91..7b7b838d2 100644 --- a/server/src/main/java/server/haengdong/persistence/ActionRepository.java +++ b/server/src/main/java/server/haengdong/persistence/ActionRepository.java @@ -3,6 +3,7 @@ import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import server.haengdong.domain.Action; import server.haengdong.domain.Event; @@ -17,5 +18,5 @@ public interface ActionRepository extends JpaRepository { ORDER BY a.sequence DESC LIMIT 1 """) - Optional findLastByEvent(Event event); + Optional findLastByEvent(@Param("event") Event event); } diff --git a/server/src/main/java/server/haengdong/persistence/EventRepository.java b/server/src/main/java/server/haengdong/persistence/EventRepository.java index 8a83d751f..5c08ca98c 100644 --- a/server/src/main/java/server/haengdong/persistence/EventRepository.java +++ b/server/src/main/java/server/haengdong/persistence/EventRepository.java @@ -7,6 +7,6 @@ @Repository public interface EventRepository extends JpaRepository { - + Optional findByToken(String token); } diff --git a/server/src/main/java/server/haengdong/persistence/MemberActionRepository.java b/server/src/main/java/server/haengdong/persistence/MemberActionRepository.java new file mode 100644 index 000000000..97d06618b --- /dev/null +++ b/server/src/main/java/server/haengdong/persistence/MemberActionRepository.java @@ -0,0 +1,16 @@ +package server.haengdong.persistence; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.Event; +import server.haengdong.domain.MemberAction; + +@Repository +public interface MemberActionRepository extends JpaRepository { + + @Query("select m from MemberAction m join fetch m.action where m.action.event = :event") + List findAllByEvent(@Param("event") Event event); +} diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberActionController.java new file mode 100644 index 000000000..e35bcfd7b --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/MemberActionController.java @@ -0,0 +1,27 @@ +package server.haengdong.presentation; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.MemberActionService; +import server.haengdong.presentation.request.MemberActionsSaveRequest; + +@RequiredArgsConstructor +@RestController +public class MemberActionController { + + private final MemberActionService memberActionService; + + @PostMapping("/api/events/{token}/actions/members") + public ResponseEntity saveMemberAction( + @PathVariable("token") String token, + @RequestBody MemberActionsSaveRequest request + ) { + memberActionService.saveMemberAction(token, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveRequest.java new file mode 100644 index 000000000..a69c51d41 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveRequest.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.request; + +import server.haengdong.application.request.MemberActionSaveAppRequest; + +public record MemberActionSaveRequest(String name, String status) { + + public MemberActionSaveAppRequest toAppRequest() { + return new MemberActionSaveAppRequest(name, status); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java new file mode 100644 index 000000000..bfe80f0ee --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.request; + +import java.util.List; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; + +public record MemberActionsSaveRequest(List actions) { + + public MemberActionsSaveAppRequest toAppRequest() { + List appRequests = actions.stream() + .map(MemberActionSaveRequest::toAppRequest) + .toList(); + + return new MemberActionsSaveAppRequest(appRequests); + } +} diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java new file mode 100644 index 000000000..a0ac9916f --- /dev/null +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -0,0 +1,216 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; + +import java.util.List; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.Action; +import server.haengdong.domain.Event; +import server.haengdong.domain.MemberAction; +import server.haengdong.domain.MemberActionStatus; +import server.haengdong.persistence.ActionRepository; +import server.haengdong.persistence.EventRepository; +import server.haengdong.persistence.MemberActionRepository; + +@SpringBootTest +class MemberActionFactoryTest { + + @Autowired + private MemberActionFactory memberActionFactory; + + @Autowired + private MemberActionRepository memberActionRepository; + + @Autowired + private ActionRepository actionRepository; + + @Autowired + private EventRepository eventRepository; + + @AfterEach + void tearDown() { + memberActionRepository.deleteAllInBatch(); + actionRepository.deleteAllInBatch(); + eventRepository.deleteAllInBatch(); + } + + @DisplayName("이전 멤버 액션이 시퀀스 기준으로 정렬되지 않은 상태에서 새로운 멤버 액션 요청을 검증한다.") + @Test + void createMemberActionsTest() { + Event event = eventRepository.save(new Event("우당탕탕 행동대장 백엔드 회식", "토다리_토큰")); + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "토다리", MemberActionStatus.OUT, 2L); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + List unorderedMemberActions = List.of(memberAction2, memberAction1); + Action startAction = new Action(event, 3L); + + assertThatThrownBy(() -> memberActionFactory.createMemberActions(request, unorderedMemberActions, startAction)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("인원 변동 액션을 생성한다.") + @Test + void createMemberActionsTest1() { + Event event = eventRepository.save(new Event("우당탕탕 행동대장 백엔드 회식", "토다리_토큰")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest memberActionsSaveAppRequest = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + Action startAction = new Action(event, 2L); + + List memberActions = memberActionFactory.createMemberActions(memberActionsSaveAppRequest, + List.of(memberAction), startAction); + + assertThat(memberActions).hasSize(1) + .extracting(MemberAction::getAction, MemberAction::getMemberName, MemberAction::getStatus) + .containsExactly( + tuple(startAction, "토다리", MemberActionStatus.OUT) + ); + } + + @DisplayName("현재 행사에 참여 중인 경우에 퇴장할 수 있다.") + @Test + void createMemberActionsTest2() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") + @Test + void createMemberActionsTest3() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action1 = new Action(event, 1L); + MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction1); + Action action2 = new Action(event, 2L); + MemberAction memberAction2 = new MemberAction(action2, "토다리", MemberActionStatus.OUT, 2L); + memberActionRepository.save(memberAction2); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "IN"))); + Action startAction = new Action(event, 3L); + + assertThatCode( + () -> memberActionFactory.createMemberActions(request, List.of(memberAction1, memberAction2), + startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장한 적 없는 경우에 입장할 수 있다.") + @Test + void createMemberActionsTest4() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") + @Test + void createMemberActionTest5() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "OUT"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(), startAction)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("행사에 이미 참여 중인 경우 다시 입장할 수 없다.") + @Test + void createMemberActionTest6() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("한 명의 사용자는 동시에 여러 번 입장할 수 없다.") + @Test + void createMemberActionTest7() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"), + new MemberActionSaveAppRequest("쿠키", "IN"))); + Action startAction = new Action(event, 1L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(), startAction)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("한 명의 사용자는 동시에 여러 번 퇴장할 수 없다.") + @Test + void createMemberActionTest8() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "OUT"), + new MemberActionSaveAppRequest("쿠키", "OUT"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("한 명의 사용자는 입장과 퇴장을 동시에 할 수 없다.") + @Test + void createMemberActionTest9() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"), + new MemberActionSaveAppRequest("쿠키", "OUT"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java new file mode 100644 index 000000000..73a7c3d9d --- /dev/null +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -0,0 +1,82 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThatCode; + +import java.util.List; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.Action; +import server.haengdong.domain.Event; +import server.haengdong.domain.MemberAction; +import server.haengdong.domain.MemberActionStatus; +import server.haengdong.persistence.ActionRepository; +import server.haengdong.persistence.EventRepository; +import server.haengdong.persistence.MemberActionRepository; + +@SpringBootTest +class MemberActionServiceTest { + + @Autowired + private MemberActionService memberActionService; + + @Autowired + private MemberActionRepository memberActionRepository; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private ActionRepository actionRepository; + + @AfterEach + void tearDown() { + memberActionRepository.deleteAllInBatch(); + actionRepository.deleteAllInBatch(); + eventRepository.deleteAllInBatch(); + } + + @DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다") + @Test + void saveMemberActionTest() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "망쵸", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("망쵸", "OUT"))))) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다") + @Test + void saveMemberActionTest1() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action actionOne = new Action(event, 1L); + MemberAction memberActionOne = new MemberAction(actionOne, "망쵸", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberActionOne); + + Action actionTwo = new Action(event, 2L); + MemberAction memberActionTwo = new MemberAction(actionTwo, "망쵸", MemberActionStatus.OUT, 1L); + memberActionRepository.save(memberActionTwo); + + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("망쵸", "IN"))))) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다") + @Test + void saveMemberActionTest2() { + MemberActionsSaveAppRequest appRequest = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("TOKEN", "OUT"))); + + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", appRequest)) + .isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index bed814ae3..a1d67f0a1 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -32,10 +32,10 @@ class EventControllerTest { @MockBean private EventService eventService; - @DisplayName("이벤트를 생성한다") + @DisplayName("이벤트를 생성한다.") @Test void saveEvent() throws Exception { - EventSaveRequest eventSaveRequest = new EventSaveRequest("test"); + EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리"); String requestBody = objectMapper.writeValueAsString(eventSaveRequest); String token = "TOKEN"; EventAppResponse eventAppResponse = new EventAppResponse(token); diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java new file mode 100644 index 000000000..8f9e71182 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -0,0 +1,49 @@ +package server.haengdong.presentation; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import server.haengdong.application.MemberActionService; +import server.haengdong.presentation.request.MemberActionSaveRequest; +import server.haengdong.presentation.request.MemberActionsSaveRequest; + +@WebMvcTest(MemberActionController.class) +class MemberActionControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private MemberActionService memberActionService; + + @DisplayName("참여자 행동을 추가한다.") + @Test + void saveMemberActionTest() throws Exception { + MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest(List.of( + new MemberActionSaveRequest("웨디", "IN"), + new MemberActionSaveRequest("소하", "IN"), + new MemberActionSaveRequest("토다리", "IN"), + new MemberActionSaveRequest("쿠키", "IN"))); + + String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); + + mockMvc.perform(post("/api/events/TOKEN/actions/members") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } +}