From 364dd9267998eb036c22190cba56bbeec5b7a3eb Mon Sep 17 00:00:00 2001 From: Juhye0k Date: Tue, 14 Apr 2026 16:54:18 +0900 Subject: [PATCH] =?UTF-8?q?chore=20:=20=EC=B5=9C=EB=8C=80=20=EC=A7=91?= =?UTF-8?q?=EC=A4=91=EC=8B=9C=EA=B0=84=203=EC=8B=9C=EA=B0=84=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/domain/StudySession.java | 4 +- .../study/service/StudySessionService.java | 2 +- .../service/StudySessionServiceTest.java | 57 +++++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gpt/geumpumtabackend/study/domain/StudySession.java b/src/main/java/com/gpt/geumpumtabackend/study/domain/StudySession.java index 82b25e7..5bc237c 100644 --- a/src/main/java/com/gpt/geumpumtabackend/study/domain/StudySession.java +++ b/src/main/java/com/gpt/geumpumtabackend/study/domain/StudySession.java @@ -47,8 +47,8 @@ public void endStudySession(LocalDateTime endTime) { status = StudyStatus.FINISHED; this.totalMillis = Duration.between(this.startTime, this.endTime).toMillis(); } - public void endMaxFocusStudySession(int maxFocusTime) { - this.endTime = this.startTime.plusMinutes(maxFocusTime); + public void endMaxFocusStudySession(int maxFocusHours) { + this.endTime = this.startTime.plusHours(maxFocusHours); status = StudyStatus.FINISHED; this.totalMillis = Duration.between(this.startTime, this.endTime).toMillis(); } diff --git a/src/main/java/com/gpt/geumpumtabackend/study/service/StudySessionService.java b/src/main/java/com/gpt/geumpumtabackend/study/service/StudySessionService.java index 0fdea44..78cba78 100644 --- a/src/main/java/com/gpt/geumpumtabackend/study/service/StudySessionService.java +++ b/src/main/java/com/gpt/geumpumtabackend/study/service/StudySessionService.java @@ -104,7 +104,7 @@ public StudySession makeStudySession(Long userId){ @Transactional public List endExpiredMaxFocusSessions() { int maxFocusHours = studyProperties.getMaxFocusHours(); - LocalDateTime cutoffTime = LocalDateTime.now().minusMinutes(maxFocusHours); + LocalDateTime cutoffTime = LocalDateTime.now().minusHours(maxFocusHours); List expiredSessions = studySessionRepository.findAllByStatusAndStartTimeBefore( StudyStatus.STARTED, cutoffTime diff --git a/src/test/java/com/gpt/geumpumtabackend/unit/study/service/StudySessionServiceTest.java b/src/test/java/com/gpt/geumpumtabackend/unit/study/service/StudySessionServiceTest.java index e570cc1..8d144b4 100644 --- a/src/test/java/com/gpt/geumpumtabackend/unit/study/service/StudySessionServiceTest.java +++ b/src/test/java/com/gpt/geumpumtabackend/unit/study/service/StudySessionServiceTest.java @@ -4,6 +4,7 @@ import com.gpt.geumpumtabackend.global.exception.ExceptionType; import com.gpt.geumpumtabackend.study.config.StudyProperties; import com.gpt.geumpumtabackend.study.domain.StudySession; +import com.gpt.geumpumtabackend.study.domain.StudyStatus; import com.gpt.geumpumtabackend.study.dto.request.StudyEndRequest; import com.gpt.geumpumtabackend.study.dto.request.StudyStartRequest; import com.gpt.geumpumtabackend.study.dto.response.StudyStartResponse; @@ -20,11 +21,13 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.time.LocalDateTime; +import java.util.List; import java.util.Optional; import static org.assertj.core.api.Assertions.*; @@ -289,6 +292,60 @@ class EndStudySession { } // 테스트 데이터 생성 헬퍼 메서드 + @Nested + @DisplayName("max focus 계산") + class MaxFocusCalculation { + + @Test + @DisplayName("max focus 종료 시간은 hour 단위로 계산된다") + void max_focus_ends_in_hour_units() { + // Given + LocalDateTime startTime = LocalDateTime.of(2024, 1, 1, 9, 0); + User testUser = createTestUser(1L, "test-user", Department.SOFTWARE); + StudySession session = new StudySession(); + + // When + session.startStudySession(startTime, testUser); + session.endMaxFocusStudySession(3); + + // Then + assertThat(session.getEndTime()).isEqualTo(startTime.plusHours(3)); + assertThat(session.getTotalMillis()).isEqualTo(10_800_000L); + assertThat(session.getStatus()).isEqualTo(StudyStatus.FINISHED); + } + + @Test + @DisplayName("만료 cutoff 는 3시간 기준으로 계산된다") + void expired_cutoff_uses_three_hours() { + // Given + User testUser = createTestUser(1L, "test-user", Department.SOFTWARE); + StudySession expiredSession = new StudySession(); + LocalDateTime sessionStartTime = LocalDateTime.now().minusHours(4); + expiredSession.startStudySession(sessionStartTime, testUser); + + given(studyProperties.getMaxFocusHours()).willReturn(3); + given(studySessionRepository.findAllByStatusAndStartTimeBefore(eq(StudyStatus.STARTED), any(LocalDateTime.class))) + .willReturn(List.of(expiredSession)); + + LocalDateTime beforeCall = LocalDateTime.now(); + + // When + List usersToNotify = studySessionService.endExpiredMaxFocusSessions(); + + // Then + LocalDateTime afterCall = LocalDateTime.now(); + ArgumentCaptor cutoffTimeCaptor = ArgumentCaptor.forClass(LocalDateTime.class); + verify(studySessionRepository).findAllByStatusAndStartTimeBefore(eq(StudyStatus.STARTED), cutoffTimeCaptor.capture()); + + assertThat(cutoffTimeCaptor.getValue()) + .isBetween(beforeCall.minusHours(3), afterCall.minusHours(3)); + assertThat(usersToNotify).containsExactly(testUser); + assertThat(expiredSession.getEndTime()).isEqualTo(sessionStartTime.plusHours(3)); + assertThat(expiredSession.getTotalMillis()).isEqualTo(10_800_000L); + assertThat(expiredSession.getStatus()).isEqualTo(StudyStatus.FINISHED); + } + } + private User createTestUser(Long id, String name, Department department) { User user = User.builder() .name(name)