Skip to content

Commit

Permalink
Merge pull request #28 from nhnacademy-be6-5ritang/feature/coupon-con…
Browse files Browse the repository at this point in the history
…troller-test

Feature/coupon controller test
  • Loading branch information
kihoo-ni authored Jul 31, 2024
2 parents 8ab6781 + 2cc7ece commit a089f5e
Show file tree
Hide file tree
Showing 37 changed files with 2,526 additions and 184 deletions.
16 changes: 6 additions & 10 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<dependencies>



<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
Expand Down Expand Up @@ -105,11 +106,11 @@
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-devtools</artifactId>-->
<!-- <scope>runtime</scope>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
Expand Down Expand Up @@ -170,11 +171,6 @@
</dependency>


<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>


<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ public CouponPolicyController(CouponPolicyService couponPolicyService) {
}

@Operation(
summary = "웰컴쿠폰 생성",
description = "웰컴쿠폰을 생성합니다"
summary = "웰컴쿠폰정책 생성",
description = "웰컴쿠폰정책을 생성합니다"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "웰컴쿠폰이 성공적으로 발행되었습니다."),
@ApiResponse(responseCode = "201", description = "웰컴쿠폰정책이 성공적으로 발행되었습니다."),
@ApiResponse(responseCode = "400", description = "잘못된 요청입니다.")
})
@AuthorizeRole({"COUPON_ADMIN", "HEAD_ADMIN"})
Expand All @@ -56,11 +56,11 @@ public ResponseEntity<Void> issueWelcomeCoupon(
return ResponseEntity.status(HttpStatus.CREATED).build();
}
@Operation(
summary = "생일쿠폰 생성",
description = "웰컴쿠폰을 생성합니다"
summary = "생일쿠폰정책 생성",
description = "생일쿠폰정책을 생성합니다"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "생일쿠폰이 성공적으로 발행되었습니다."),
@ApiResponse(responseCode = "201", description = "생일쿠폰정책이 성공적으로 발행되었습니다."),
@ApiResponse(responseCode = "400", description = "잘못된 요청입니다.")
})
@AuthorizeRole({"COUPON_ADMIN", "HEAD_ADMIN"})
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,4 @@
public interface CustomCouponPolicyRepository {
Page<CouponPolicyResponseDTO> findAllWithBooksAndCategories(Pageable pageable, Map<Long, BookCoupon.BookInfo> bookIdMap, Map<Long, CategoryCoupon.CategoryInfo> categoryIdMap);
Optional<CouponPolicy> findLatestCouponPolicyByType(String type);

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ public Page<CouponPolicyResponseDTO> findAllWithBooksAndCategories(Pageable page
Map<Long, CategoryCoupon.CategoryInfo> categoryIdMap) {
QCouponPolicy couponPolicy = QCouponPolicy.couponPolicy;





// Fetch coupon policies with pagination and ordering
List<CouponPolicyResponseDTO> couponPolicies = queryFactory
.selectFrom(couponPolicy)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public CouponTemplateController(CouponTemplateService couponTemplateService) {
}




@Operation(summary = "쿠폰 템플릿 생성", description = "새로운 쿠폰 템플릿을 생성합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "쿠폰 템플릿이 성공적으로 생성되었습니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
.anyRequest().permitAll()
)
.addFilterBefore(ipAddressFilter, UsernamePasswordAuthenticationFilter.class)
// .addFilterAfter(new JwtFilter(jwtUtils, tokenReissueClient), IpAddressFilter.class)
.addFilterBefore(new JwtFilter(jwtUtils, tokenReissueClient, accessTokenExpiresIn, refreshTokenExpiresIn),
UsernamePasswordAuthenticationFilter.class)
.sessionManagement((session) -> session
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,13 @@
import com.nhnacademy.bookstorecoupon.global.exception.GlobalException;
import com.nhnacademy.bookstorecoupon.global.exception.payload.ErrorStatus;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler({GlobalException.class})
public ResponseEntity<ErrorStatus> handleExceptionGlobally(GlobalException ex) {
ErrorStatus errorStatus=ex.getErrorStatus();


return new ResponseEntity<>(errorStatus, errorStatus.getStatus());
}

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorStatus> processValidationError(MethodArgumentNotValidException exception) {
BindingResult bindingResult = exception.getBindingResult();
Expand All @@ -47,8 +44,29 @@ public ResponseEntity<ErrorStatus> processValidationError(MethodArgumentNotValid
LocalDateTime.now()
);

log.error("validation 에러: {}", exception.getMessage());
return new ResponseEntity<>(errorStatus, HttpStatus.BAD_REQUEST);

}



@ExceptionHandler({GlobalException.class})
public ResponseEntity<ErrorStatus> handleGlobalException(GlobalException ex) {
ErrorStatus errorStatus=ex.getErrorStatus();

log.error("글로벌 에러: {}", ex.getMessage());
return new ResponseEntity<>(errorStatus, errorStatus.getStatus());
}



@ExceptionHandler({Exception.class})
public ResponseEntity<Void> handleException(Exception ex) {


log.error("서버에러: {}", ex.getMessage());
return ResponseEntity.status(500).build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,6 @@ public void issueBirthdayCoupon() {
.orElseThrow(() -> new CouponPolicyNotFoundException(ErrorStatus.from("최신 생일쿠폰 정책을 찾을 수 없습니다.", HttpStatus.NOT_FOUND, LocalDateTime.now())));

// 생일 목록에 있는 각 사용자에게 쿠폰을 발행


birthdayList.forEach(user -> {

UserAndCoupon userAndCoupon = UserAndCoupon.builder()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package com.nhnacademy.bookstorecoupon.auth.jwt.filter;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import com.nhnacademy.bookstorecoupon.auth.jwt.client.TokenReissueClient;
import com.nhnacademy.bookstorecoupon.auth.jwt.dto.request.ReissueTokenRequest;
import com.nhnacademy.bookstorecoupon.auth.jwt.dto.response.ReissueTokensResponse;
import com.nhnacademy.bookstorecoupon.auth.jwt.utils.JwtUtils;

import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

class JwtFilterTest {


@InjectMocks
private JwtFilter jwtFilter;

@Mock
private JwtUtils jwtUtils;

@Mock
private TokenReissueClient tokenReissueClient;

@Mock
private HttpServletRequest request;

@Mock
private HttpServletResponse response;

@Mock
private FilterChain filterChain;

@Mock
private PrintWriter writer; // Add a mock for PrintWriter

private static final String VALID_ACCESS_TOKEN = "valid-access-token";
private static final String EXPIRED_ACCESS_TOKEN = "expired-access-token";
private static final String VALID_REFRESH_TOKEN = "valid-refresh-token";
private static final String NEW_ACCESS_TOKEN = "new-access-token";
private static final String NEW_REFRESH_TOKEN = "new-refresh-token";

@BeforeEach
void setup() {
MockitoAnnotations.openMocks(this);
try {
when(response.getWriter()).thenReturn(writer); // Mock PrintWriter
} catch (IOException e) {
e.printStackTrace();
}
}

@Test
void testDoFilterInternal_ValidToken() throws Exception {
when(request.getHeader("Authorization")).thenReturn(VALID_ACCESS_TOKEN);
when(request.getHeader("Refresh-Token")).thenReturn(VALID_REFRESH_TOKEN);
when(jwtUtils.validateToken(VALID_ACCESS_TOKEN)).thenReturn(null);
when(jwtUtils.getUserIdFromToken(VALID_ACCESS_TOKEN)).thenReturn(123L);
when(jwtUtils.getUserRolesFromToken(VALID_ACCESS_TOKEN)).thenReturn(Collections.singletonList("ROLE_USER"));

jwtFilter.doFilterInternal(request, response, filterChain);

verify(filterChain).doFilter(request, response);
verifyNoMoreInteractions(response);
}

@Test
void testDoFilterInternal_ExpiredToken() throws Exception {
when(request.getHeader("Authorization")).thenReturn(EXPIRED_ACCESS_TOKEN);
when(request.getHeader("Refresh-Token")).thenReturn(VALID_REFRESH_TOKEN);
when(jwtUtils.validateToken(EXPIRED_ACCESS_TOKEN)).thenReturn("만료된 토큰입니다.");
when(tokenReissueClient.reissueTokensWithRefreshToken(any(ReissueTokenRequest.class)))
.thenReturn(ResponseEntity.ok(new ReissueTokensResponse(NEW_ACCESS_TOKEN, NEW_REFRESH_TOKEN)));

jwtFilter.doFilterInternal(request, response, filterChain);

ArgumentCaptor<String> authHeaderCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<String> refreshHeaderCaptor = ArgumentCaptor.forClass(String.class);
verify(response).setHeader(eq("New-Authorization"), authHeaderCaptor.capture());
verify(response).setHeader(eq("New-Refresh-Token"), refreshHeaderCaptor.capture());

assertEquals(NEW_ACCESS_TOKEN, authHeaderCaptor.getValue());
assertEquals(NEW_REFRESH_TOKEN, refreshHeaderCaptor.getValue());
verify(filterChain).doFilter(request, response);
}

@Test
void testDoFilterInternal_TokenReissueFailure() throws Exception {
when(request.getHeader("Authorization")).thenReturn(EXPIRED_ACCESS_TOKEN);
when(request.getHeader("Refresh-Token")).thenReturn(VALID_REFRESH_TOKEN);
when(jwtUtils.validateToken(EXPIRED_ACCESS_TOKEN)).thenReturn("만료된 토큰입니다.");
when(tokenReissueClient.reissueTokensWithRefreshToken(any(ReissueTokenRequest.class)))
.thenReturn(ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null));

jwtFilter.doFilterInternal(request, response, filterChain);

verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
verify(writer).print("토큰 재발급에 실패했습니다. 다시 로그인해주세요."); // Mock PrintWriter behavior
verifyNoMoreInteractions(filterChain);
}

@Test
void testDoFilterInternal_InvalidToken() throws Exception {
when(request.getHeader("Authorization")).thenReturn(VALID_ACCESS_TOKEN);
when(request.getHeader("Refresh-Token")).thenReturn(VALID_REFRESH_TOKEN);
when(jwtUtils.validateToken(VALID_ACCESS_TOKEN)).thenReturn("유효하지 않은 토큰입니다.");

jwtFilter.doFilterInternal(request, response, filterChain);

verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
verify(writer).print("유효하지 않은 토큰입니다."); // Mock PrintWriter behavior
verifyNoMoreInteractions(filterChain);
}

@Test
void testDoFilterInternal_NoTokenProvided() throws Exception {
when(request.getHeader("Authorization")).thenReturn(null);

jwtFilter.doFilterInternal(request, response, filterChain);

verify(filterChain).doFilter(request, response);
verifyNoMoreInteractions(response);
}

}
Loading

0 comments on commit a089f5e

Please sign in to comment.