From b3699083951ff7e86c3e4e58474cc865bbf83e5d Mon Sep 17 00:00:00 2001 From: ddingmin Date: Tue, 13 Feb 2024 00:28:11 +0900 Subject: [PATCH 1/3] release: 0.4.2 (#205) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test: test 명 완성 * refactor: Instant를 모두 LocalDateTime으로 변경 (#200) * fix: 알림이 가지 않는 버그 수정 * test: 인증 단위 테스트 구현 (#202) * refactor: JwtAuthenticationFilter 불필요한 로직 제거 (#198) * refactor: SecurityValue 패키지 이동 (#198) * test: 인증 관련 단위 테스트 구현 (#198) * test: 인증 관련 단위 테스트 구현 (#198) * test: JwtAuthenticationFilterTest 리팩토링 (#198) * feat: 로그인한 유저가 북마크한 모임 조회 (#204) * feat: 로그인한 유저가 북마크한 모임 조회 * test: 테스트 코드에 로그인 로직 추가 --------- Co-authored-by: choidongkuen Co-authored-by: devxb Co-authored-by: xb205 <62425964+devxb@users.noreply.github.com> --- .../net/teumteum/alert/app/AlertHandler.java | 1 - .../teumteum/alert/domain/AlertService.java | 5 +- .../alert/infra/FcmAlertPublisher.java | 1 - .../filter/JwtAuthenticationFilter.java | 6 +- .../meeting/controller/MeetingController.java | 5 +- .../meeting/domain/MeetingSpecification.java | 4 + .../service/MeetingAlertPublisher.java | 3 - .../meeting/service/MeetingService.java | 7 +- .../integration/MeetingIntegrationTest.java | 8 ++ .../auth/controller/AuthControllerTest.java | 8 +- .../unit/auth/service/AuthServiceTest.java | 4 +- .../unit/{auth => }/common/SecurityValue.java | 2 +- .../JwtAuthenticationEntryPointTest.java | 64 +++++++++ .../security/JwtAuthenticationFilterTest.java | 136 ++++++++++++++++++ .../user/controller/UserControllerTest.java | 8 +- .../unit/user/service/UserServiceTest.java | 5 +- 16 files changed, 237 insertions(+), 30 deletions(-) rename src/test/java/net/teumteum/unit/{auth => }/common/SecurityValue.java (90%) create mode 100644 src/test/java/net/teumteum/unit/core/security/JwtAuthenticationEntryPointTest.java create mode 100644 src/test/java/net/teumteum/unit/core/security/JwtAuthenticationFilterTest.java diff --git a/src/main/java/net/teumteum/alert/app/AlertHandler.java b/src/main/java/net/teumteum/alert/app/AlertHandler.java index 080eb35e..86e6bc69 100644 --- a/src/main/java/net/teumteum/alert/app/AlertHandler.java +++ b/src/main/java/net/teumteum/alert/app/AlertHandler.java @@ -32,7 +32,6 @@ public class AlertHandler { @Async(ALERT_EXECUTOR) @EventListener(BeforeMeetingAlerted.class) public void handleBeforeMeetingAlerts(BeforeMeetingAlerted alerted) { - System.out.println(">>> handleBeforeMeetingAlerts(" + alerted + " )"); userAlertService.findAllByUserId(alerted.userIds()) .stream() .map(userAlert -> Pair.of(userAlert.getToken(), diff --git a/src/main/java/net/teumteum/alert/domain/AlertService.java b/src/main/java/net/teumteum/alert/domain/AlertService.java index b8c86283..bf664223 100644 --- a/src/main/java/net/teumteum/alert/domain/AlertService.java +++ b/src/main/java/net/teumteum/alert/domain/AlertService.java @@ -1,7 +1,7 @@ package net.teumteum.alert.domain; import java.time.LocalDateTime; -import java.time.temporal.ChronoUnit; +import java.time.ZoneId; import lombok.RequiredArgsConstructor; import net.teumteum.alert.domain.response.AlertsResponse; import org.springframework.scheduling.annotation.Scheduled; @@ -33,7 +33,8 @@ public AlertsResponse findAllByUserId(Long userId) { @Transactional @Scheduled(cron = EVERY_12AM) public void deleteOneMonthBeforeAlert() { - var deleteTargets = alertRepository.findAllByCreatedAt(LocalDateTime.now().minus(1, ChronoUnit.MONTHS)); + var deleteTargets = alertRepository.findAllByCreatedAt( + LocalDateTime.now(ZoneId.of("Asia/Seoul")).minusMonths(1)); alertRepository.deleteAllInBatch(deleteTargets); } } diff --git a/src/main/java/net/teumteum/alert/infra/FcmAlertPublisher.java b/src/main/java/net/teumteum/alert/infra/FcmAlertPublisher.java index de3c51a7..7b9c8309 100644 --- a/src/main/java/net/teumteum/alert/infra/FcmAlertPublisher.java +++ b/src/main/java/net/teumteum/alert/infra/FcmAlertPublisher.java @@ -36,7 +36,6 @@ public class FcmAlertPublisher implements AlertPublisher { @Async(FCM_ALERT_EXECUTOR) public void publish(String token, Alert alert, Map data) { var message = buildMessage(token, alert, data); - System.out.println(">>> message" + message); publishWithRetry(0, message, null); } diff --git a/src/main/java/net/teumteum/core/security/filter/JwtAuthenticationFilter.java b/src/main/java/net/teumteum/core/security/filter/JwtAuthenticationFilter.java index db33f357..20ef8e31 100644 --- a/src/main/java/net/teumteum/core/security/filter/JwtAuthenticationFilter.java +++ b/src/main/java/net/teumteum/core/security/filter/JwtAuthenticationFilter.java @@ -15,7 +15,6 @@ import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; -import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; @@ -31,7 +30,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtProperty jwtProperty; @Override - protected void doFilterInternal(HttpServletRequest request, + public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (request.getMethod().equals("OPTIONS")) { @@ -73,10 +72,9 @@ private void saveUserAuthentication(User user) { private String resolveTokenFromRequest(HttpServletRequest request) { String token = request.getHeader(jwtProperty.getAccess().getHeader()); - if (!ObjectUtils.isEmpty(token) && token.toLowerCase().startsWith(jwtProperty.getBearer().toLowerCase())) { + if (token.toLowerCase().startsWith(jwtProperty.getBearer().toLowerCase())) { return token.substring(7); } - setRequestAttribute(request, "요청에 대한 JWT 파싱 과정에서 문제가 발생했습니다."); return null; } diff --git a/src/main/java/net/teumteum/meeting/controller/MeetingController.java b/src/main/java/net/teumteum/meeting/controller/MeetingController.java index c3eab0b8..27410d42 100644 --- a/src/main/java/net/teumteum/meeting/controller/MeetingController.java +++ b/src/main/java/net/teumteum/meeting/controller/MeetingController.java @@ -62,10 +62,11 @@ public PageDto getMeetingsByCondition( @RequestParam(value = "topic", required = false) Topic topic, @RequestParam(value = "meetingAreaStreet", required = false) String meetingAreaStreet, @RequestParam(value = "participantUserId", required = false) Long participantUserId, + @RequestParam(value = "isBookmarked", required = false) Boolean isBookmarked, @RequestParam(value = "searchWord", required = false) String searchWord) { - + Long userId = securityService.getCurrentUserId(); return meetingService.getMeetingsBySpecification(pageable, topic, meetingAreaStreet, participantUserId, - searchWord, isOpen); + searchWord, isBookmarked, isOpen, userId); } @PutMapping("/{meetingId}") diff --git a/src/main/java/net/teumteum/meeting/domain/MeetingSpecification.java b/src/main/java/net/teumteum/meeting/domain/MeetingSpecification.java index fc2bc861..a0cb0ff2 100644 --- a/src/main/java/net/teumteum/meeting/domain/MeetingSpecification.java +++ b/src/main/java/net/teumteum/meeting/domain/MeetingSpecification.java @@ -39,4 +39,8 @@ public static Specification withParticipantUserId(Long participantUserI participantUserId); } + public static Specification withBookmarkedUserId(Long userId) { + return (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.join("bookmarkedUserIds"), userId); + } + } diff --git a/src/main/java/net/teumteum/meeting/service/MeetingAlertPublisher.java b/src/main/java/net/teumteum/meeting/service/MeetingAlertPublisher.java index 40e3ef53..402c057d 100644 --- a/src/main/java/net/teumteum/meeting/service/MeetingAlertPublisher.java +++ b/src/main/java/net/teumteum/meeting/service/MeetingAlertPublisher.java @@ -26,11 +26,8 @@ public class MeetingAlertPublisher { @Scheduled(cron = EVERY_ONE_MINUTES) public void alertBeforeMeeting() { var alertStart = LocalDateTime.now(ZoneId.of("Asia/Seoul")).plusMinutes(5).withNano(0).withSecond(0); - System.out.println(">>> alertStart = " + alertStart); var alertEnd = alertStart.plusMinutes(1).withNano(0).withSecond(0); - System.out.println(">>> alertEnd = " + alertEnd); var alertTargets = meetingRepository.findAlertMeetings(alertStart, alertEnd); - alertTargets.forEach(target -> System.out.println(">>> target id = " + target.getId())); alertTargets.forEach(meeting -> eventPublisher.publishEvent( new BeforeMeetingAlerted(meeting.getParticipantUserIds()) ) diff --git a/src/main/java/net/teumteum/meeting/service/MeetingService.java b/src/main/java/net/teumteum/meeting/service/MeetingService.java index 00f3975e..d87db102 100644 --- a/src/main/java/net/teumteum/meeting/service/MeetingService.java +++ b/src/main/java/net/teumteum/meeting/service/MeetingService.java @@ -94,9 +94,8 @@ public void deleteMeeting(Long meetingId, Long userId) { } @Transactional(readOnly = true) - public PageDto getMeetingsBySpecification(Pageable pageable, Topic topic, - String meetingAreaStreet, - Long participantUserId, String searchWord, boolean isOpen) { + public PageDto getMeetingsBySpecification(Pageable pageable, Topic topic, String meetingAreaStreet, + Long participantUserId, String searchWord, Boolean isBookmarked, boolean isOpen, Long userId) { Specification spec = MeetingSpecification.withIsOpen(isOpen); @@ -110,6 +109,8 @@ public PageDto getMeetingsBySpecification(Pageable pageable, T spec = MeetingSpecification.withSearchWordInTitle(searchWord) .or(MeetingSpecification.withSearchWordInIntroduction(searchWord)) .and(MeetingSpecification.withIsOpen(isOpen)); + } else if (Boolean.TRUE.equals(isBookmarked)) { + spec = spec.and(MeetingSpecification.withBookmarkedUserId(userId)); } var meetings = meetingRepository.findAll(spec, pageable); diff --git a/src/test/java/net/teumteum/integration/MeetingIntegrationTest.java b/src/test/java/net/teumteum/integration/MeetingIntegrationTest.java index bec162c2..dc45f2c3 100644 --- a/src/test/java/net/teumteum/integration/MeetingIntegrationTest.java +++ b/src/test/java/net/teumteum/integration/MeetingIntegrationTest.java @@ -141,6 +141,8 @@ class Find_meeting_list_api { @DisplayName("존재하는 topic이 주어지면 페이지 네이션을 적용해 미팅 목록을 최신순으로 응답한다.") void Return_meeting_list_if_topic_and_page_nation_received() { // given + var user = repository.saveAndGetUser(); + securityContextSetting.set(user.getId()); var size = 2; var openMeetingsByTopic = repository.saveAndGetOpenMeetingsByTopic(size, Topic.스터디); var closeTopicMeetingsByTopic = repository.saveAndGetOpenMeetingsByTopic(size, Topic.고민_나누기); @@ -169,6 +171,8 @@ void Return_meeting_list_if_topic_and_page_nation_received() { @DisplayName("제목이나 설명에 존재하는 검색어가 주어지면 페이지 네이션을 적용해 미팅 목록을 최신순으로 응답한다.") void Return_meeting_list_if_search_word_and_page_nation_received() { // given + var user = repository.saveAndGetUser(); + securityContextSetting.set(user.getId()); var size = 2; var openMeetingsByTitle = repository.saveAndGetOpenMeetingsByTitle(size, "개발자 스터디"); var closeMeetingsByTitle = repository.saveAndGetCloseMeetingsByTitle(size, "개발자 스터디"); @@ -201,6 +205,8 @@ void Return_meeting_list_if_search_word_and_page_nation_received() { @DisplayName("참여자 id가 주어지면 페이지 네이션을 적용해 미팅 목록을 최신순으로 응답한다.") void Return_meeting_list_if_participant_user_id_and_page_nation_received() { // given + var user = repository.saveAndGetUser(); + securityContextSetting.set(user.getId()); var size = 2; var openMeetingsByParticipantUserId = repository.saveAndGetOpenMeetingsByParticipantUserId(size, 2L); var closeMeetingsByParticipantUserId = repository.saveAndGetCloseMeetingsByParticipantUserId(size, 2L); @@ -229,6 +235,8 @@ void Return_meeting_list_if_participant_user_id_and_page_nation_received() { @DisplayName("요청한 size와 page보다 더 많은 데이터가 존재하면, hasNext를 true로 응답한다.") void Return_has_next_true_if_more_data_exists_than_requested_size_and_page() { // given + var user = repository.saveAndGetUser(); + securityContextSetting.set(user.getId()); var size = 10; var openMeetingsByTopic = repository.saveAndGetOpenMeetingsByTopic(size, Topic.스터디); diff --git a/src/test/java/net/teumteum/unit/auth/controller/AuthControllerTest.java b/src/test/java/net/teumteum/unit/auth/controller/AuthControllerTest.java index cea80e23..b5437bb1 100644 --- a/src/test/java/net/teumteum/unit/auth/controller/AuthControllerTest.java +++ b/src/test/java/net/teumteum/unit/auth/controller/AuthControllerTest.java @@ -1,10 +1,10 @@ package net.teumteum.unit.auth.controller; -import static net.teumteum.unit.auth.common.SecurityValue.INVALID_ACCESS_TOKEN; -import static net.teumteum.unit.auth.common.SecurityValue.INVALID_REFRESH_TOKEN; -import static net.teumteum.unit.auth.common.SecurityValue.VALID_ACCESS_TOKEN; -import static net.teumteum.unit.auth.common.SecurityValue.VALID_REFRESH_TOKEN; +import static net.teumteum.unit.common.SecurityValue.INVALID_ACCESS_TOKEN; +import static net.teumteum.unit.common.SecurityValue.INVALID_REFRESH_TOKEN; +import static net.teumteum.unit.common.SecurityValue.VALID_ACCESS_TOKEN; +import static net.teumteum.unit.common.SecurityValue.VALID_REFRESH_TOKEN; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.springframework.http.HttpHeaders.AUTHORIZATION; diff --git a/src/test/java/net/teumteum/unit/auth/service/AuthServiceTest.java b/src/test/java/net/teumteum/unit/auth/service/AuthServiceTest.java index 3163c935..ef7b5512 100644 --- a/src/test/java/net/teumteum/unit/auth/service/AuthServiceTest.java +++ b/src/test/java/net/teumteum/unit/auth/service/AuthServiceTest.java @@ -1,8 +1,8 @@ package net.teumteum.unit.auth.service; import static net.teumteum.core.security.Authenticated.네이버; -import static net.teumteum.unit.auth.common.SecurityValue.INVALID_ACCESS_TOKEN; -import static net.teumteum.unit.auth.common.SecurityValue.VALID_REFRESH_TOKEN; +import static net.teumteum.unit.common.SecurityValue.INVALID_ACCESS_TOKEN; +import static net.teumteum.unit.common.SecurityValue.VALID_REFRESH_TOKEN; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; diff --git a/src/test/java/net/teumteum/unit/auth/common/SecurityValue.java b/src/test/java/net/teumteum/unit/common/SecurityValue.java similarity index 90% rename from src/test/java/net/teumteum/unit/auth/common/SecurityValue.java rename to src/test/java/net/teumteum/unit/common/SecurityValue.java index e82b8cc6..4bbee619 100644 --- a/src/test/java/net/teumteum/unit/auth/common/SecurityValue.java +++ b/src/test/java/net/teumteum/unit/common/SecurityValue.java @@ -1,4 +1,4 @@ -package net.teumteum.unit.auth.common; +package net.teumteum.unit.common; public final class SecurityValue { diff --git a/src/test/java/net/teumteum/unit/core/security/JwtAuthenticationEntryPointTest.java b/src/test/java/net/teumteum/unit/core/security/JwtAuthenticationEntryPointTest.java new file mode 100644 index 00000000..42920f4b --- /dev/null +++ b/src/test/java/net/teumteum/unit/core/security/JwtAuthenticationEntryPointTest.java @@ -0,0 +1,64 @@ +package net.teumteum.unit.core.security; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import net.teumteum.core.error.ErrorResponse; +import net.teumteum.core.security.filter.JwtAuthenticationEntryPoint; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.web.DelegatingServletOutputStream; +import org.springframework.security.core.AuthenticationException; + +@ExtendWith(MockitoExtension.class) +@DisplayName("JwtAuthenticationEntryPoint 단위 테스트의") +public class JwtAuthenticationEntryPointTest { + + private static final String ATTRIBUTE_NAME = "exception"; + @Mock + private ObjectMapper objectMapper; + @Mock + private AuthenticationException authenticationException; + @Mock + private HttpServletRequest request; + @Mock + private HttpServletResponse response; + @InjectMocks + private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; + + @Nested + @DisplayName("JwtAuthenticationFilter 에서 인증 예외가 발생시") + class When_authentication_error_occurs_from_filter { + + @Test + @DisplayName("알맞은 예외 메시지와 관련 응답을 반환한다.") + void Return_error_response_with_message() throws IOException { + // given + var errorMessage = "Authentication Exception Occurred"; + var outputStream = new ByteArrayOutputStream(); + + given(request.getAttribute(ATTRIBUTE_NAME)).willReturn(errorMessage); + given(response.getOutputStream()).willReturn(new DelegatingServletOutputStream(outputStream)); + + // when + jwtAuthenticationEntryPoint.commence(request, response, authenticationException); + + // then + verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED); + verify(objectMapper, times(1)).writeValue(any(OutputStream.class), any(ErrorResponse.class)); + } + } +} diff --git a/src/test/java/net/teumteum/unit/core/security/JwtAuthenticationFilterTest.java b/src/test/java/net/teumteum/unit/core/security/JwtAuthenticationFilterTest.java new file mode 100644 index 00000000..ca8badb7 --- /dev/null +++ b/src/test/java/net/teumteum/unit/core/security/JwtAuthenticationFilterTest.java @@ -0,0 +1,136 @@ +package net.teumteum.unit.core.security; + +import static net.teumteum.unit.common.SecurityValue.INVALID_ACCESS_TOKEN; +import static net.teumteum.unit.common.SecurityValue.VALID_ACCESS_TOKEN; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import java.io.IOException; +import net.teumteum.auth.service.AuthService; +import net.teumteum.core.property.JwtProperty; +import net.teumteum.core.security.UserAuthentication; +import net.teumteum.core.security.filter.JwtAuthenticationFilter; +import net.teumteum.core.security.service.JwtService; +import net.teumteum.user.domain.UserFixture; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.security.core.context.SecurityContextHolder; + +@ExtendWith(MockitoExtension.class) +@DisplayName("JwtAuthenticationFilter 단위 테스트의") +public class JwtAuthenticationFilterTest { + + private static final String ATTRIBUTE_NAME = "exception"; + @Mock + private JwtService jwtService; + @Mock + private AuthService authService; + @Mock + private JwtProperty jwtProperty; + @Mock + private JwtProperty.Access access; + @Mock + private FilterChain filterChain; + @InjectMocks + private JwtAuthenticationFilter jwtAuthenticationFilter; + + @Nested + @DisplayName("API 요청시 JWT 파싱 및 회원 조회 로직은") + class Api_request_with_valid_jwt_unit { + + @BeforeEach + @AfterEach + void clearSecurityContextHolder() { + SecurityContextHolder.clearContext(); + } + + @Test + @DisplayName("유효한 JWT 인 경우, JWT 을 파싱하고 성공적으로 UserAuthentication 을 SecurityContext 에 저장한다.") + void Parsing_jwt_and_save_user_in_security_context() throws ServletException, IOException { + // given + var request = new MockHttpServletRequest(); + var response = new MockHttpServletResponse(); + + given(jwtProperty.getAccess()).willReturn(access); + given(jwtProperty.getAccess().getHeader()).willReturn("Authorization"); + given(jwtProperty.getBearer()).willReturn("Bearer"); + + request.addHeader(jwtProperty.getAccess().getHeader(), + jwtProperty.getBearer() + " " + VALID_ACCESS_TOKEN); + + var user = UserFixture.getIdUser(); + + given(jwtService.validateToken(anyString())).willReturn(true); + given(authService.findUserByAccessToken(anyString())).willReturn(user); + + // when + jwtAuthenticationFilter.doFilterInternal(request, response, filterChain); + + // then + var authentication = SecurityContextHolder.getContext().getAuthentication(); + assertThat(authentication).isInstanceOf(UserAuthentication.class); + } + + @Test + @DisplayName("유효하지 않은 JWT 와 함께 요청이 들어오면, 요청 처리를 중단하고 에러 메세지를 반환한다.") + void Return_error_when_jwt_is_invalid() throws ServletException, IOException { + // given + var request = new MockHttpServletRequest(); + var response = new MockHttpServletResponse(); + + given(jwtProperty.getAccess()).willReturn(access); + given(jwtProperty.getAccess().getHeader()).willReturn("Authorization"); + given(jwtProperty.getBearer()).willReturn("Bearer"); + + request.addHeader(jwtProperty.getAccess().getHeader(), + jwtProperty.getBearer() + " " + INVALID_ACCESS_TOKEN); + + given(jwtService.validateToken(anyString())).willReturn(false); + + // when + jwtAuthenticationFilter.doFilterInternal(request, response, filterChain); + + // then + assertThat(request.getAttribute(ATTRIBUTE_NAME)).isEqualTo("요청에 대한 JWT 가 유효하지 않습니다."); + var authentication = SecurityContextHolder.getContext().getAuthentication(); + assertThat(authentication).isNull(); + verify(filterChain, times(1)).doFilter(request, response); + } + + @Test + @DisplayName("JWT 가 존재하지 않는 경우, 요청 처리를 중단하고 에러 메세지를 반환한다.") + void Return_error_when_jwt_is_not_exist() throws ServletException, IOException { + // given + var request = new MockHttpServletRequest(); + var response = new MockHttpServletResponse(); + + given(jwtProperty.getAccess()).willReturn(access); + given(jwtProperty.getAccess().getHeader()).willReturn("Authorization"); + given(jwtProperty.getBearer()).willReturn("Bearer"); + + request.addHeader(jwtProperty.getAccess().getHeader(), + jwtProperty.getBearer() + " "); + + // when + jwtAuthenticationFilter.doFilterInternal(request, response, filterChain); + + // then + assertThat(request.getAttribute(ATTRIBUTE_NAME)).isEqualTo("요청에 대한 JWT 정보가 존재하지 않습니다."); + verify(jwtService, times(0)).validateToken(anyString()); + } + } +} diff --git a/src/test/java/net/teumteum/unit/user/controller/UserControllerTest.java b/src/test/java/net/teumteum/unit/user/controller/UserControllerTest.java index caee082c..f425e053 100644 --- a/src/test/java/net/teumteum/unit/user/controller/UserControllerTest.java +++ b/src/test/java/net/teumteum/unit/user/controller/UserControllerTest.java @@ -1,7 +1,7 @@ package net.teumteum.unit.user.controller; -import static net.teumteum.unit.auth.common.SecurityValue.VALID_ACCESS_TOKEN; -import static net.teumteum.unit.auth.common.SecurityValue.VALID_REFRESH_TOKEN; +import static net.teumteum.unit.common.SecurityValue.VALID_ACCESS_TOKEN; +import static net.teumteum.unit.common.SecurityValue.VALID_REFRESH_TOKEN; import static net.teumteum.user.domain.Review.별로에요; import static net.teumteum.user.domain.Review.최고에요; import static org.hamcrest.Matchers.hasSize; @@ -267,11 +267,9 @@ void Get_user_reviews_with_200_ok() throws Exception { class Logout_user_api_unit { @Test - @DisplayName("") + @DisplayName("로그인한 회원의 로그아웃을 진행하고, 200 OK 을 반환합니다.") void Logout_user_with_200_ok() throws Exception { // given - var userId = 1L; - doNothing().when(userService).logout(anyLong()); // when && then diff --git a/src/test/java/net/teumteum/unit/user/service/UserServiceTest.java b/src/test/java/net/teumteum/unit/user/service/UserServiceTest.java index b92508fe..f6823533 100644 --- a/src/test/java/net/teumteum/unit/user/service/UserServiceTest.java +++ b/src/test/java/net/teumteum/unit/user/service/UserServiceTest.java @@ -1,7 +1,8 @@ package net.teumteum.unit.user.service; -import static net.teumteum.unit.auth.common.SecurityValue.VALID_ACCESS_TOKEN; -import static net.teumteum.unit.auth.common.SecurityValue.VALID_REFRESH_TOKEN; + +import static net.teumteum.unit.common.SecurityValue.VALID_ACCESS_TOKEN; +import static net.teumteum.unit.common.SecurityValue.VALID_REFRESH_TOKEN; import static net.teumteum.user.domain.Review.별로에요; import static net.teumteum.user.domain.Review.최고에요; import static org.assertj.core.api.Assertions.assertThat; From 09acf554199db84e2451cbbcd6cd066441430a4f Mon Sep 17 00:00:00 2001 From: ddingmin Date: Tue, 13 Feb 2024 00:58:07 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=EC=B6=A9=EB=8F=8C=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0=20(#210)=20(#211)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/net/teumteum/meeting/service/MeetingService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/net/teumteum/meeting/service/MeetingService.java b/src/main/java/net/teumteum/meeting/service/MeetingService.java index 2657f43e..99cfc412 100644 --- a/src/main/java/net/teumteum/meeting/service/MeetingService.java +++ b/src/main/java/net/teumteum/meeting/service/MeetingService.java @@ -112,7 +112,6 @@ public PageDto getMeetingsBySpecification(Pageable pageable, T } else if (Boolean.TRUE.equals(isBookmarked)) { spec = MeetingSpecification.withBookmarkedUserId(userId); } - var meetings = meetingRepository.findAll(spec, pageable); return PageDto.of(MeetingsResponse.of(meetings.getContent()), meetings.hasNext()); From a14fffba533e6598b2548a0ce759d6482e06c578 Mon Sep 17 00:00:00 2001 From: ddingmin Date: Tue, 13 Feb 2024 01:07:26 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20=EC=B6=A9=EB=8F=8C=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0=20(#210)=20(#212)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit