diff --git a/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/_core/errors/BaseException.java b/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/_core/errors/BaseException.java index b614112c..073e2ccd 100644 --- a/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/_core/errors/BaseException.java +++ b/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/_core/errors/BaseException.java @@ -6,22 +6,29 @@ // 모든 에러의 메시지를 관리 @RequiredArgsConstructor public enum BaseException { + // user 관련 USER_NOT_FOUND("서비스를 탈퇴했거나 가입하지 않은 유저의 요청입니다.", 404), - ACCESS_TOKEN_EXPIRED("access-token이 만료되었습니다. refresh-token 으로 다시 요청해주세요.", 403), - ALL_TOKEN_EXPIRED("모든 토큰이 만료되었습니다. 다시 로그인 해야합니다.", 401), - TOKEN_NOT_FOUND("토큰을 찾을 수 없습니다.", 404), - TOKEN_NOT_VALID("로그인 토큰이 유효하지 않습니다. 다시 로그인 해주세요", 403), - INVALID_TOKEN_ACCESS_DETECTED("올바르지 않은 접근입니다. 다시 로그인 해주세요.", 403), - TOKEN_REFRESH_FORBIDDEN("토큰을 갱신할 수 없습니다.", 403), + PLANNER_NOT_FOUND("서비스를 탈퇴하거나 가입하지 않은 플래너입니다", 404), USER_EMAIL_EXIST("동일한 이메일이 존재합니다.", 400), USER_EMAIL_NOT_FOUND("이메일을 찾을 수 없습니다 : ", 400), USER_ROLE_WRONG("role은 플래너, 또는 예비 부부만 가능합니다.", 400), USER_PASSWORD_WRONG("패스워드를 잘못 입력하셨습니다",400), USER_PASSWORD_NOT_SAME("패스워드1과 패스워드2는 동일해야 합니다.: ", 400), USER_ALREADY_PREMIUM("이미 프리미엄 회원입니다.", 400), - USER_TOKEN_WRONG("잘못된 토큰입니다", 401), - PAYMENT_WRONG_INFORMATION("잘못된 결제 정보입니다.", 404), USER_UNEXPECTED_ERROR("[User] 예상치 못한 문제가 발생했습니다.", 500), + + // token 관련 + ACCESS_TOKEN_EXPIRED("access-token이 만료되었습니다. refresh-token 으로 다시 요청해주세요.", 403), + ALL_TOKEN_EXPIRED("모든 토큰이 만료되었습니다. 다시 로그인 해야합니다.", 401), + TOKEN_NOT_FOUND("토큰을 찾을 수 없습니다.", 404), + TOKEN_NOT_VALID("로그인 토큰이 유효하지 않습니다. 다시 로그인 해주세요", 403), + TOKEN_REFRESH_FORBIDDEN("토큰을 갱신할 수 없습니다.", 403), + INVALID_TOKEN_ACCESS_DETECTED("올바르지 않은 접근입니다. 다시 로그인 해주세요.", 403), + + // 결제 관련 + PAYMENT_WRONG_INFORMATION("잘못된 결제 정보입니다.", 404), + + //포트폴리오 관련 PORTFOLIO_NOT_FOUND("해당하는 플래너의 포트폴리오가 삭제되었거나 존재하지 않습니다.", 404), PORTFOLIO_ALREADY_EXIST("해당 플래너의 포트폴리오가 이미 존재합니다. 포트폴리오는 플래너당 하나만 생성할 수 있습니다.", 400), PORTFOLIO_IMAGE_NOT_FOUND("포트폴리오 이미지를 불러올 수 없습니다.", 404), @@ -29,17 +36,25 @@ public enum BaseException { PORTFOLIO_IMAGE_ENCODING_ERROR("이미지 인코딩 과정에서 오류가 발생했습니다.", 500), PORTFOLIO_CREATE_DIRECTORY_ERROR("포트폴리오 폴더 생성 과정에서 오류가 발생했습니다.", 500), PORTFOLIO_CLEAN_DIRECTORY_ERROR("포트폴리오 폴더를 비우는 과정에서 오류가 발생했습니다.", 500), - PERMISSION_DENIED_METHOD_ACCESS("사용할 수 없는 기능입니다.", 403), - DATABASE_ERROR("데이터베이스 에러입니다", 500), + + // 견적서 관련 QUOTATIONS_NOT_ALL_CONFIRMED("확정되지 않은 견적서가 있습니다.",400), - NO_QUOTATION_TO_CONFIRM("확정할 견적서가 없습니다",400), - NOT_CONFIRMED_ALL_QUOTATIONS("견적서 전체 확정을 해야 합니다.", 400), - MATCHING_NOT_FOUND("매칭 내역을 찾을 수 없습니다.", 404), + QUOTATION_NOTHING_TO_CONFIRM("확정할 견적서가 없습니다",400), + QUOTATION_NOT_CONFIRMED_ALL("견적서 전체 확정을 해야 합니다.", 400), QUOTATION_NOT_FOUND("해당 견적서를 찾을 수 없습니다.", 404), QUOTATION_CHANGE_DENIED("견적서가 이미 확정되어 수정할 수 없습니다.", 403), QUOTATION_ACCESS_DENIED("해당 매칭 내역에 접근할 수 없습니다.", 403), QUOTATION_ALREADY_CONFIRMED("견적서가 확정된 상태입니다.", 403), - MATCHING_ALREADY_CONFIRMED("전체 확정되어 견적서를 추가할 수 없습니다.", 403); + + // 매칭 관련 + MATCHING_ALREADY_CONFIRMED("전체 확정되어 견적서를 추가할 수 없습니다.", 403), + MATCHING_NOT_FOUND("매칭 내역을 찾을 수 없습니다.", 404), + MATCHING_ALREADY_EXIST("이미 존재하는 매칭입니다.", 400), + + // 공통 + PERMISSION_DENIED_METHOD_ACCESS("사용할 수 없는 기능입니다.", 403), + DATABASE_ERROR("데이터베이스 에러입니다", 500), + ; @Getter private final String message; diff --git a/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/_core/security/JwtAuthenticationFilter.java b/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/_core/security/JwtAuthenticationFilter.java index fbd93d94..eb412af1 100644 --- a/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/_core/security/JwtAuthenticationFilter.java +++ b/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/_core/security/JwtAuthenticationFilter.java @@ -124,7 +124,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse } catch (TokenExpiredException tee) { log.error("access token 만료됨"); // access token 만 만료 시에는 403 에러 전달 - throw new ForbiddenException(BaseException.ACCESS_TOKEN_EXPIRED.getMessage()); + //throw new ForbiddenException(BaseException.ACCESS_TOKEN_EXPIRED.getMessage()); } catch (JWTDecodeException jde) { log.error("잘못된 access token"); } catch (Exception e){ diff --git a/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/_core/security/JwtExceptionFilter.java b/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/_core/security/JwtExceptionFilter.java index 100687e0..6b295eb0 100644 --- a/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/_core/security/JwtExceptionFilter.java +++ b/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/_core/security/JwtExceptionFilter.java @@ -46,7 +46,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse filterResponseUtils.notFound(response, notFoundException); } catch (JWTCreationException | JWTVerificationException e) { - filterResponseUtils.unAuthorized(response, new UnauthorizedException(BaseException.USER_TOKEN_WRONG)); + filterResponseUtils.unAuthorized(response, new UnauthorizedException(BaseException.TOKEN_NOT_FOUND)); } } } \ No newline at end of file diff --git a/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/_core/security/SecurityConfig.java b/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/_core/security/SecurityConfig.java index 13e373ac..8d55cdb7 100644 --- a/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/_core/security/SecurityConfig.java +++ b/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/_core/security/SecurityConfig.java @@ -96,6 +96,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .requestMatchers( new AntPathRequestMatcher("/user/**"), new AntPathRequestMatcher("/portfolios/**"), + new AntPathRequestMatcher("/myportfolio"), new AntPathRequestMatcher("/chat/**"), new AntPathRequestMatcher("/quotations/**"), new AntPathRequestMatcher("/payments/**") diff --git a/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/match/MatchJPARepository.java b/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/match/MatchJPARepository.java index 407be7d5..4aec7520 100644 --- a/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/match/MatchJPARepository.java +++ b/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/match/MatchJPARepository.java @@ -14,4 +14,7 @@ public interface MatchJPARepository extends JpaRepository { @Query("select m from Match m where m.planner = :planner and m.confirmedAt != null order by m.confirmedAt desc limit 10") List findLatestTenByPlanner(@Param("planner") Planner planner); + + @Query("select m from Match m where m.planner = :planner and m.couple = :couple") + List findByCoupleAndPlanner(@Param("couple") Couple couple, @Param("planner") Planner plannerId); } diff --git a/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/match/MatchResponse.java b/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/match/MatchResponse.java new file mode 100644 index 00000000..2e50b390 --- /dev/null +++ b/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/match/MatchResponse.java @@ -0,0 +1,20 @@ +package com.kakao.sunsuwedding.match; + +import com.kakao.sunsuwedding.user.couple.Couple; +import com.kakao.sunsuwedding.user.planner.Planner; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; + +public class MatchResponse { + + @Getter @Setter + public static class ChatByIdDTO { + Long chatId; + + public ChatByIdDTO(Match match){ + this.chatId = match.getId(); + } + } +} diff --git a/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/match/MatchRestController.java b/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/match/MatchRestController.java index d8715c4d..c4cd5581 100644 --- a/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/match/MatchRestController.java +++ b/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/match/MatchRestController.java @@ -21,8 +21,8 @@ public class MatchRestController { public ResponseEntity addChat( @AuthenticationPrincipal CustomUserDetails userDetails, @Valid @RequestBody MatchRequest.AddMatchDTO request) { - matchService.addChat(userDetails.getInfo(), request); - return ResponseEntity.ok().body(ApiUtils.success(null)); + MatchResponse.ChatByIdDTO response = matchService.addChat(userDetails.getInfo(), request); + return ResponseEntity.ok().body(ApiUtils.success(response)); } // Match Delete : isActive 필드 false diff --git a/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/match/MatchService.java b/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/match/MatchService.java index 26e3fbf5..989d56d9 100644 --- a/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/match/MatchService.java +++ b/sunsu-wedding/src/main/java/com/kakao/sunsuwedding/match/MatchService.java @@ -68,7 +68,7 @@ public void deleteChat(Pair info, Long matchId) { List quotations = quotationJPARepository.findAllByMatch(match); // 견적서 존재하는데 전체 확정이 되지 않은 경우, 채팅방 삭제 불가 if ((!quotations.isEmpty()) && (match.getStatus().equals(MatchStatus.UNCONFIRMED))) { - throw new BadRequestException(BaseException.NOT_CONFIRMED_ALL_QUOTATIONS); + throw new BadRequestException(BaseException.QUOTATION_NOT_CONFIRMED_ALL); } // 전체확정 됐거나, 견적서가 없는 경우 채팅방 삭제 matchJPARepository.delete(match); @@ -77,7 +77,7 @@ public void deleteChat(Pair info, Long matchId) { private Pair isAllConfirmed(Match match) { List quotations = quotationJPARepository.findAllByMatch(match); if (quotations.isEmpty()) { - throw new BadRequestException(BaseException.NO_QUOTATION_TO_CONFIRM); + throw new BadRequestException(BaseException.QUOTATION_NOTHING_TO_CONFIRM); } else { // 모든 견적서 확정 됐는지 여부 구하기 @@ -91,7 +91,9 @@ private Pair isAllConfirmed(Match match) { } } - public void addChat(Pair user, MatchRequest.AddMatchDTO requestDTO) { + @Transactional + public MatchResponse.ChatByIdDTO addChat(Pair user, MatchRequest.AddMatchDTO requestDTO) { + Long coupleId = user.getSecond(); Long plannerId = requestDTO.getPlannerId(); @@ -99,9 +101,17 @@ public void addChat(Pair user, MatchRequest.AddMatchDTO requestDTO () -> new NotFoundException(BaseException.USER_NOT_FOUND.getMessage() + " couple") ); Planner planner = plannerJPARepository.findById(plannerId).orElseThrow( - () -> new NotFoundException(BaseException.USER_NOT_FOUND.getMessage() + " planner") + () -> new NotFoundException(BaseException.PLANNER_NOT_FOUND.getMessage() + " planner") ); - matchJPARepository.save(requestDTO.toMatchEntity(couple, planner)); + List matches = matchJPARepository.findByCoupleAndPlanner(couple, planner); + + // 플래너, 유저 매칭은 최대 한 개까지만 생성 가능 + if (!matches.isEmpty()){ + throw new BadRequestException(BaseException.MATCHING_ALREADY_EXIST); + } + Match match = matchJPARepository.save(requestDTO.toMatchEntity(couple, planner)); + + return new MatchResponse.ChatByIdDTO(match); } private void permissionCheck(Pair info, Match match) { diff --git a/sunsu-wedding/src/main/resources/db/teardown.sql b/sunsu-wedding/src/main/resources/db/teardown.sql index 1dc4aa5d..219bc8d9 100644 --- a/sunsu-wedding/src/main/resources/db/teardown.sql +++ b/sunsu-wedding/src/main/resources/db/teardown.sql @@ -1,5 +1,6 @@ SET REFERENTIAL_INTEGRITY FALSE; truncate table user_tb; +truncate table token_tb; truncate table portfolio_tb; truncate table imageitem_tb; truncate table priceitem_tb; @@ -8,7 +9,7 @@ truncate table quotation_tb; SET REFERENTIAL_INTEGRITY TRUE; -- planner 비밀번호 : planner1234! -INSERT INTO user_tb (`id`,`email`,`password`,`username`,`created_at`,`payed_at`,`grade`, `is_active`, `dtype`) VALUES ('2','planner@gmail.com','{bcrypt}$2a$10$89SwVjyXVDhK3GFcN4c8Bu3kQlNiWqjaTvgiXaCi9D/1eWx2w7CBa','planner','2023-09-16 01:06:55.00','2023-09-20 15:26:55.00','NORMAL', 'true', 'planner'); +INSERT INTO user_tb (`id`,`email`,`password`,`username`,`created_at`,`payed_at`,`grade`, `is_active`, `dtype`, `order_id`, `payed_amount`) VALUES ('2','planner@gmail.com','{bcrypt}$2a$10$89SwVjyXVDhK3GFcN4c8Bu3kQlNiWqjaTvgiXaCi9D/1eWx2w7CBa','planner','2023-09-16 01:06:55.00','2023-09-20 15:26:55.00','NORMAL', 'true', 'planner', 'orderId', '5000'); INSERT INTO user_tb (`id`,`email`,`password`,`username`,`created_at`,`payed_at`,`grade`, `is_active`, `dtype`) VALUES ('3','planner2@gmail.com','{bcrypt}$2a$10$89SwVjyXVDhK3GFcN4c8Bu3kQlNiWqjaTvgiXaCi9D/1eWx2w7CBa','planner2','2023-09-16 01:06:55.00','2023-09-20 15:26:55.00','PREMIUM', 'true', 'planner'); INSERT INTO user_tb (`id`,`email`,`password`,`username`,`created_at`,`payed_at`,`grade`, `is_active`, `dtype`) VALUES ('6','planner5@gmail.com','{bcrypt}$2a$10$89SwVjyXVDhK3GFcN4c8Bu3kQlNiWqjaTvgiXaCi9D/1eWx2w7CBa','planner5','2023-09-16 01:06:55.00','2023-09-20 15:26:55.00','PREMIUM', 'true', 'planner'); INSERT INTO user_tb (`id`,`email`,`password`,`username`,`created_at`,`payed_at`,`grade`, `is_active`, `dtype`) VALUES ('7','planner6@gmail.com','{bcrypt}$2a$10$89SwVjyXVDhK3GFcN4c8Bu3kQlNiWqjaTvgiXaCi9D/1eWx2w7CBa','planner6','2023-09-16 01:06:55.00','2023-09-20 15:26:55.00','PREMIUM', 'true', 'planner'); @@ -26,6 +27,11 @@ INSERT INTO user_tb (`id`,`email`,`password`,`username`,`created_at`,`payed_at`, -- couple 비밀번호 : couple1234! INSERT INTO user_tb (`id`,`email`,`password`,`username`,`created_at`,`payed_at`,`grade`, `is_active`, `dtype`) VALUES ('4','couple@gmail.com','{bcrypt}$2a$10$bKgX34po45/xYw1Dd8C81OYW4dkkVQV5lHd7a.06m1gBX689XERA.','couple','2023-09-16 01:06:55.00','2023-09-20 15:26:55.00','NORMAL', 'true', 'couple'); INSERT INTO user_tb (`id`,`email`,`password`,`username`,`created_at`,`payed_at`,`grade`, `is_active`, `dtype`) VALUES ('5','couple2@gmail.com','{bcrypt}$2a$10$bKgX34po45/xYw1Dd8C81OYW4dkkVQV5lHd7a.06m1gBX689XERA.','couple2','2023-09-16 01:06:55.00','2023-09-20 15:26:55.00','PREMIUM', 'true', 'couple'); +INSERT INTO user_tb (`id`,`email`,`password`,`username`,`created_at`,`payed_at`,`grade`, `is_active`, `dtype`) VALUES ('18','couple3@gmail.com','{bcrypt}$2a$10$bKgX34po45/xYw1Dd8C81OYW4dkkVQV5lHd7a.06m1gBX689XERA.','couple3','2023-09-16 01:06:55.00','2023-09-20 15:26:55.00','PREMIUM', 'true', 'couple'); + +-- token +--INSERT INTO token_tb (`id`,`user_id`,`access_token`,`refresh_token`) VALUES ('2', '3','accesToken1', 'refreshToken1'); +--INSERT INTO token_tb (`id`,`user_id`,`access_token`,`refresh_token`) VALUES ('3', '4','accesToken2', 'refreshToken2'); INSERT INTO portfolio_tb (`id`, `planner_id`, `title`, `description`, `location`, `career`, `partner_company`, `total_price`, `contract_count`, `avg_price`, `min_price`, `max_price`, `created_at`) VALUES ('1', '2', 'test1', 'test1', '부산', 'none', 'none', '1000000', '10', '1000000', '1000000', '1000000', '2023-09-15 15:26:55.00'); INSERT INTO portfolio_tb (`id`, `planner_id`, `title`, `description`, `location`, `career`, `partner_company`, `total_price`, `contract_count`, `avg_price`, `min_price`, `max_price`, `created_at`) VALUES ('2', '3', 'test2', 'test2', '부산', 'none', 'none', '2000000', '20', '2000000', '2000000', '2000000', '2023-09-22 15:26:55.00'); @@ -61,14 +67,16 @@ INSERT INTO imageitem_tb (`id`, `portfolio_id`, `origin_file_name`, `file_path`, INSERT INTO imageitem_tb (`id`, `portfolio_id`, `origin_file_name`, `file_path`, `file_size`, `thumbnail`) VALUES ('9', '2', '2-4.jpg', '/Users/seokjun/Downloads/images/', '522499', 'false'); INSERT INTO imageitem_tb (`id`, `portfolio_id`, `origin_file_name`, `file_path`, `file_size`, `thumbnail`) VALUES ('10', '2', '2-5.jpg', '/Users/seokjun/Downloads/images/', '522499', 'false'); -INSERT INTO match_tb (`id`, `planner_id`, `couple_id`, `status`, `price`, `confirmed_price`, `confirmed_at`, `created_at`, `is_active`) VALUES ('1', '2', '4', 'CONFIRMED', '1000000', '1000000', '2023-10-08 08:30:12.00', '2023-10-08 08:30:12.00', 'true'); +--INSERT INTO match_tb (`id`, `planner_id`, `couple_id`, `status`, `price`, `confirmed_price`, `confirmed_at`, `created_at`, `is_active`) VALUES ('1', '2', '4', 'CONFIRMED', '1000000', '1000000', '2023-10-08 08:30:12.00', '2023-10-08 08:30:12.00', 'true'); INSERT INTO match_tb (`id`, `planner_id`, `couple_id`, `status`, `price`, `confirmed_price`, `confirmed_at`, `created_at`, `is_active`) VALUES ('2', '2', '4', 'UNCONFIRMED', '1000000', '0', '2023-10-08 08:30:12.00', '2023-10-08 08:30:12.00', 'true'); INSERT INTO match_tb (`id`, `planner_id`, `couple_id`, `status`, `price`, `confirmed_price`, `confirmed_at`, `created_at`, `is_active`) VALUES ('3', '2', '5', 'UNCONFIRMED', '1000000', '0', '2023-10-08 08:30:12.00', '2023-10-08 08:30:12.00', 'true'); INSERT INTO match_tb (`id`, `planner_id`, `couple_id`, `status`, `price`, `confirmed_price`, `confirmed_at`, `created_at`, `is_active`) VALUES ('4', '2', '4', 'UNCONFIRMED', '1000000', '0', '2023-10-08 08:30:12.00', '2023-10-08 08:30:12.00', 'true'); INSERT INTO match_tb (`id`, `planner_id`, `couple_id`, `status`, `price`, `confirmed_price`, `confirmed_at`, `created_at`, `is_active`) VALUES ('5', '3', '4', 'UNCONFIRMED', '1000000', '0', '2023-10-08 08:30:12.00', '2023-10-08 08:30:12.00', 'true'); +INSERT INTO match_tb (`id`, `planner_id`, `couple_id`, `status`, `price`, `confirmed_price`, `confirmed_at`, `created_at`, `is_active`) VALUES ('6', '2', '4', 'CONFIRMED', '1000000', '1000000', '2023-10-08 08:30:12.00', '2023-10-08 08:30:12.00', 'true'); + -INSERT INTO quotation_tb (`id`, `match_id`, `title`, `price`, `company`, `description`, `status`, `modified_at`, `created_at`, `is_active`) VALUES ('1', '1', 'test', '1000000', 'abc', 'asdf', 'CONFIRMED', '2023-10-08 08:30:12.00', '2023-10-08 08:30:12.00', 'true'); -INSERT INTO quotation_tb (`id`, `match_id`, `title`, `price`, `company`, `description`, `status`, `modified_at`, `created_at`, `is_active`) VALUES ('2', '1', 'test2', '1000000', 'abc2', 'asdf2', 'CONFIRMED', '2023-10-08 08:30:12.00', '2023-10-08 08:30:12.00', 'true'); +INSERT INTO quotation_tb (`id`, `match_id`, `title`, `price`, `company`, `description`, `status`, `modified_at`, `created_at`, `is_active`) VALUES ('1', '6', 'test', '1000000', 'abc', 'asdf', 'CONFIRMED', '2023-10-08 08:30:12.00', '2023-10-08 08:30:12.00', 'true'); +INSERT INTO quotation_tb (`id`, `match_id`, `title`, `price`, `company`, `description`, `status`, `modified_at`, `created_at`, `is_active`) VALUES ('2', '6', 'test2', '1000000', 'abc2', 'asdf2', 'CONFIRMED', '2023-10-08 08:30:12.00', '2023-10-08 08:30:12.00', 'true'); INSERT INTO quotation_tb (`id`, `match_id`, `title`, `price`, `company`, `description`, `status`, `modified_at`, `created_at`, `is_active`) VALUES ('3', '2', 'test', '1000000', 'abc', 'asdf', 'UNCONFIRMED', '2023-10-08 08:30:12.00', '2023-10-08 08:30:12.00', 'true'); INSERT INTO quotation_tb (`id`, `match_id`, `title`, `price`, `company`, `description`, `status`, `modified_at`, `created_at`, `is_active`) VALUES ('4', '2', 'test2', '1000000', 'abc2', 'asdf2', 'UNCONFIRMED', '2023-10-08 08:30:12.00', '2023-10-08 08:30:12.00', 'true'); INSERT INTO quotation_tb (`id`, `match_id`, `title`, `price`, `company`, `description`, `status`, `modified_at`, `created_at`, `is_active`) VALUES ('5', '3', 'test2', '1000000', 'abc2', 'asdf2', 'UNCONFIRMED', '2023-10-08 08:30:12.00', '2023-10-08 08:30:12.00', 'true'); diff --git a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/_core/DummyEntity.java b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/_core/DummyEntity.java index c7bb1aed..18e09a6f 100644 --- a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/_core/DummyEntity.java +++ b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/_core/DummyEntity.java @@ -1,10 +1,12 @@ package com.kakao.sunsuwedding._core; +import com.kakao.sunsuwedding.match.Match; +import com.kakao.sunsuwedding.user.base_user.User; import com.kakao.sunsuwedding.user.constant.Grade; import com.kakao.sunsuwedding.user.couple.Couple; import com.kakao.sunsuwedding.user.planner.Planner; +import com.kakao.sunsuwedding.user.token.Token; import org.springframework.cglib.core.Local; -import org.springframework.security.core.userdetails.User; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @@ -15,7 +17,7 @@ protected Couple newCouple(String username){ return Couple.builder() .email(username+"@nate.com") .password("couple1234!") - .username("couple") + .username(username) .createdAt(LocalDateTime.now()) .isActive(true) .grade(Grade.NORMAL) @@ -25,10 +27,35 @@ protected Planner newPlanner(String username){ return Planner.builder() .email(username+"@nate.com") .password("planner1234!") - .username("planner") + .username(username) .createdAt(LocalDateTime.now()) .isActive(true) .grade(Grade.NORMAL) .build(); } + protected Planner unActivePlanner(String username){ + return Planner.builder() + .email(username+"@nate.com") + .password("planner1234!") + .username(username) + .createdAt(LocalDateTime.now()) + .isActive(false) + .grade(Grade.NORMAL) + .build(); + } + protected Match newMatch(Couple couple, Planner planner, Long price){ + return Match.builder() + .couple(couple) + .planner(planner) + .price(price) + .build(); + } + protected Token newToken(User user){ + return Token.builder() + .user(user) + .accessToken("accessToken") + .refreshToken("refreshToken") + .build(); + } + } diff --git a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/match/MatchRepositoryTest.java b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/match/MatchRepositoryTest.java new file mode 100644 index 00000000..c8b26fc5 --- /dev/null +++ b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/match/MatchRepositoryTest.java @@ -0,0 +1,139 @@ +package com.kakao.sunsuwedding.match; + +import com.kakao.sunsuwedding._core.DummyEntity; +import com.kakao.sunsuwedding.user.couple.Couple; +import com.kakao.sunsuwedding.user.couple.CoupleJPARepository; +import com.kakao.sunsuwedding.user.planner.Planner; +import com.kakao.sunsuwedding.user.planner.PlannerJPARepository; +import jakarta.persistence.EntityManager; +import org.junit.jupiter.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureDataJpa; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@AutoConfigureDataJpa +@DataJpaTest +public class MatchRepositoryTest extends DummyEntity { + + @Autowired + private MatchJPARepository matchJPARepository; + + @Autowired + private CoupleJPARepository coupleJPARepository; + + @Autowired + private PlannerJPARepository plannerJPARepository; + + private Long id1, id2; + + Couple couple; + Planner planner, planner2; + + @Autowired + private EntityManager em; + + + @BeforeEach + void setUp() { + couple = coupleJPARepository.save(newCouple("newcouple")); + planner = plannerJPARepository.save(newPlanner("newplanner")); + planner2 = plannerJPARepository.save(newPlanner("newplanner2")); + + Match m1 = newMatch(couple, planner,0L); + Match m2 = newMatch(couple, planner2,0L); + + id1 = matchJPARepository.save(m1).getId(); + id2 = matchJPARepository.save(m2).getId(); + + em.clear(); + } + + @AfterEach + void tearDown() { + matchJPARepository.deleteAll(); + } + + @Test + @DisplayName("id로 매칭 찾기") + void findMatchById(){ + // when + Match match = matchJPARepository.findById(id1).orElseThrow( + () -> new RuntimeException("매칭 내역을 찾을 수 없습니다.") + ); + + // then + assertThat(match.getPlanner().getEmail()).isEqualTo("newplanner@nate.com"); + assertThat(match.getPrice()).isEqualTo(0L); + assertThat(match.getStatus()).isEqualTo(MatchStatus.UNCONFIRMED); + } + + @Test + @DisplayName("플래너로 매칭 찾기") + void findMatchByPlanner(){ + + // when + List match = matchJPARepository.findAllByPlanner(planner); + + // then + assertThat(match.get(0).getCouple().getEmail()).isEqualTo("newcouple@nate.com"); + assertThat(match.get(0).getPlanner().getEmail()).isEqualTo("newplanner@nate.com"); + assertThat(match.get(0).getPrice()).isEqualTo(0L); + assertThat(match.get(0).getStatus()).isEqualTo(MatchStatus.UNCONFIRMED); + } + + @Test + @DisplayName("커플, 플래너로 매칭 찾기") + void findMatchByCoupleAndPlanner(){ + // when + List match = matchJPARepository.findByCoupleAndPlanner(couple, planner); + + // then + assertThat(match.size()).isEqualTo(1L); + assertThat(match.get(0).getCouple().getEmail()).isEqualTo("newcouple@nate.com"); + assertThat(match.get(0).getPlanner().getEmail()).isEqualTo("newplanner@nate.com"); + assertThat(match.get(0).getPrice()).isEqualTo(0L); + } + + @Test + @DisplayName("플래너 전체확정된 거래내역 10개 들고오기") + void findLatestTenByPlanner(){ + // when + List match = matchJPARepository.findLatestTenByPlanner(planner2); + + // then + assertThat(match.size()).isEqualTo(0L); + } + + @Test + @DisplayName("저장하기") + void saveMatch(){ + // when + Couple couple = coupleJPARepository.save(newCouple("test1")); + Planner planner = plannerJPARepository.save(newPlanner("test2")); + Match match = matchJPARepository.save(newMatch(couple, planner, 100L)); + + // then + assertThat(match.getPlanner().getEmail()).isEqualTo("test2@nate.com"); + assertThat(match.getPrice()).isEqualTo(100L); + assertThat(match.getStatus()).isEqualTo(MatchStatus.UNCONFIRMED); + } + + @Test + @DisplayName("삭제하기") + void deleteMatch(){ + // when + long previous_counts = matchJPARepository.count(); + Match match = matchJPARepository.findById(id1).orElseThrow( + () -> new RuntimeException("존재하지 않는 match id 입니다.") + ); + matchJPARepository.delete(match); + + // then + assertThat(matchJPARepository.count()).isEqualTo(previous_counts - 1); + } + +} \ No newline at end of file diff --git a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/match/MatchRestControllerTest.java b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/match/MatchRestControllerTest.java index 00324227..e1c855c3 100644 --- a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/match/MatchRestControllerTest.java +++ b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/match/MatchRestControllerTest.java @@ -1,5 +1,6 @@ package com.kakao.sunsuwedding.match; +import com.fasterxml.jackson.databind.ObjectMapper; import com.kakao.sunsuwedding._core.security.SecurityConfig; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -9,6 +10,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; import org.springframework.security.test.context.support.WithUserDetails; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.jdbc.Sql; @@ -20,7 +22,6 @@ @Import({ SecurityConfig.class, }) - @ActiveProfiles("test") @Sql("classpath:db/teardown.sql") @AutoConfigureMockMvc @@ -30,10 +31,62 @@ public class MatchRestControllerTest { private static final Logger logger = LoggerFactory.getLogger(MatchRestControllerTest.class); @Autowired - MockMvc mvc; + private MockMvc mvc; + + @Autowired + private ObjectMapper om; // ============ 채팅방 생성 테스트 ============ + @DisplayName("채팅방 생성 성공 테스트") + @Test + @WithUserDetails("couple3@gmail.com") + public void match_create_success_test() throws Exception { + //given + MatchRequest.AddMatchDTO requestDTO = new MatchRequest.AddMatchDTO(); + requestDTO.setPlannerId(16L); + String requestBody = om.writeValueAsString(requestDTO); + + //when + ResultActions result = mvc.perform( + MockMvcRequestBuilders + .post("/chat") + .content(requestBody) + .contentType(MediaType.APPLICATION_JSON) + ); + + String responseBody = result.andReturn().getResponse().getContentAsString(); + logger.debug("테스트 : " + responseBody); + + // then + result.andExpect(MockMvcResultMatchers.jsonPath("$.success").value("true")); + result.andExpect(MockMvcResultMatchers.jsonPath("$.response.chatId").value(1L)); + } + @DisplayName("채팅방 생성 실패 테스트 - 이미 존재하는 매칭내역") + @Test + @WithUserDetails("couple@gmail.com") + public void match_create_fail_test() throws Exception { + //given + MatchRequest.AddMatchDTO requestDTO = new MatchRequest.AddMatchDTO(); + requestDTO.setPlannerId(2L); + String requestBody = om.writeValueAsString(requestDTO); + + //when + ResultActions result = mvc.perform( + MockMvcRequestBuilders + .post("/chat") + .content(requestBody) + .contentType(MediaType.APPLICATION_JSON) + ); + + String responseBody = result.andReturn().getResponse().getContentAsString(); + logger.debug("테스트 : " + responseBody); + + // then + result.andExpect(MockMvcResultMatchers.jsonPath("$.success").value("false")); + result.andExpect(MockMvcResultMatchers.jsonPath("$.error.message").value("이미 존재하는 매칭입니다.")); + result.andExpect(MockMvcResultMatchers.jsonPath("$.error.status").value(400)); + } // ============ 채팅방 삭제 테스트 ============ @DisplayName("채팅방 삭제 성공 테스트") @@ -41,7 +94,7 @@ public class MatchRestControllerTest { @WithUserDetails("couple@gmail.com") public void match_delete_success_test() throws Exception { //given - Long matchId = 1L; + Long matchId = 6L; //when ResultActions result = mvc.perform( diff --git a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/payment/PaymentRestControllerTest.java b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/payment/PaymentRestControllerTest.java new file mode 100644 index 00000000..61d82799 --- /dev/null +++ b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/payment/PaymentRestControllerTest.java @@ -0,0 +1,196 @@ +package com.kakao.sunsuwedding.payment; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.kakao.sunsuwedding._core.security.SecurityConfig; +import com.kakao.sunsuwedding.user.UserRestControllerTest; +import com.kakao.sunsuwedding.user.payment.PaymentRequest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithUserDetails; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@Import({ + SecurityConfig.class, +}) +@ActiveProfiles("test") +@Sql("classpath:db/teardown.sql") +@AutoConfigureMockMvc +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) +public class PaymentRestControllerTest { + + private static final Logger logger = LoggerFactory.getLogger(UserRestControllerTest.class); + + @Autowired + private MockMvc mvc; + + @Autowired + private ObjectMapper om; + + // ============ 결제 데이터 저장 테스트 ============ + @DisplayName("결제 데이터 저장 성공 테스트") + @Test + @WithUserDetails("couple@gmail.com") + void save_payment_success() throws Exception { + // given + PaymentRequest.SaveDTO requestDTO = new PaymentRequest.SaveDTO(); + requestDTO.setAmount(1000L); + requestDTO.setOrderId("orderId1"); + String requestBody = om.writeValueAsString(requestDTO); + + // when + ResultActions result = mvc.perform( + MockMvcRequestBuilders + .post("/payments/save") + .content(requestBody) + .contentType(MediaType.APPLICATION_JSON) + ); + + String responseBody = result.andReturn().getResponse().getContentAsString(); + logger.debug("테스트 : " + responseBody); + + // then + result.andExpect(MockMvcResultMatchers.jsonPath("$.success").value("true")); + } + + @DisplayName("결제 데이터 저장 실패 테스트 - orderId가 비어있음") + @Test + @WithUserDetails("couple@gmail.com") + void save_payment_fail() throws Exception { + // given + PaymentRequest.SaveDTO requestDTO = new PaymentRequest.SaveDTO(); + requestDTO.setAmount(1000L); + requestDTO.setOrderId(""); + String requestBody = om.writeValueAsString(requestDTO); + + // when + ResultActions result = mvc.perform( + MockMvcRequestBuilders + .post("/payments/save") + .content(requestBody) + .contentType(MediaType.APPLICATION_JSON) + ); + + String responseBody = result.andReturn().getResponse().getContentAsString(); + logger.debug("테스트 : " + responseBody); + + // then + result.andExpect(MockMvcResultMatchers.jsonPath("$.success").value("false")); + result.andExpect(MockMvcResultMatchers.jsonPath("$.error.status").value("400")); + result.andExpect(MockMvcResultMatchers.jsonPath("$.error.message").value("orderId는 비어있으면 안됩니다.")); + } + + // ============ 결제 정보 검증 테스트 ============ + @DisplayName("결제 정보 검증 성공 테스트") + @Test + @WithUserDetails("planner@gmail.com") + void confirm_payment_success() throws Exception { + // when + PaymentRequest.ConfirmDTO requestDTO = new PaymentRequest.ConfirmDTO(); + requestDTO.setAmount(5000L); + requestDTO.setOrderId("orderId"); + String requestBody = om.writeValueAsString(requestDTO); + + //given + ResultActions result = mvc.perform( + MockMvcRequestBuilders + .post("/payments/confirm") + .content(requestBody) + .contentType(MediaType.APPLICATION_JSON) + ); + + String responseBody = result.andReturn().getResponse().getContentAsString(); + logger.debug("테스트 : " + responseBody); + result.andExpect(MockMvcResultMatchers.jsonPath("$.success").value("true")); + } + + @DisplayName("결제 정보 검증 실패 테스트 - 잘못된 amount") + @Test + @WithUserDetails("planner@gmail.com") + void confirm_payment_fail() throws Exception { + // when + PaymentRequest.ConfirmDTO requestDTO = new PaymentRequest.ConfirmDTO(); + requestDTO.setAmount(1000L); + requestDTO.setOrderId("orderId"); + String requestBody = om.writeValueAsString(requestDTO); + + //given + ResultActions result = mvc.perform( + MockMvcRequestBuilders + .post("/payments/confirm") + .content(requestBody) + .contentType(MediaType.APPLICATION_JSON) + ); + + String responseBody = result.andReturn().getResponse().getContentAsString(); + logger.debug("테스트 : " + responseBody); + result.andExpect(MockMvcResultMatchers.jsonPath("$.success").value("true")); + result.andExpect(MockMvcResultMatchers.jsonPath("$.response").value("fail")); + } + + // ============ 유저 등급 업그레이드 테스트 ============ + @DisplayName("유저 등급 업그레이드 성공 테스트") + @Test + @WithUserDetails("planner@gmail.com") + void user_upgrade_success() throws Exception { + // given + PaymentRequest.UpgradeDTO requestDTO = new PaymentRequest.UpgradeDTO(); + requestDTO.setAmount(5000L); + requestDTO.setOrderId("orderId"); + requestDTO.setStatus("DONE"); + String requestBody = om.writeValueAsString(requestDTO); + + // when + ResultActions result = mvc.perform( + MockMvcRequestBuilders + .post("/payments/upgrade") + .content(requestBody) + .contentType(MediaType.APPLICATION_JSON) + ); + + String responseBody = result.andReturn().getResponse().getContentAsString(); + logger.debug("테스트 : " + responseBody); + + // then + result.andExpect(MockMvcResultMatchers.jsonPath("$.success").value("true")); + + } + @DisplayName("유저 등급 업그레이드 실패 테스트") + @Test + @WithUserDetails("planner@gmail.com") + void user_upgrade_fail() throws Exception { + // given + PaymentRequest.UpgradeDTO requestDTO = new PaymentRequest.UpgradeDTO(); + requestDTO.setAmount(5000L); + requestDTO.setOrderId("orderId"); + requestDTO.setStatus("EXPIRED"); + String requestBody = om.writeValueAsString(requestDTO); + + // when + ResultActions result = mvc.perform( + MockMvcRequestBuilders + .post("/payments/upgrade") + .content(requestBody) + .contentType(MediaType.APPLICATION_JSON) + ); + + String responseBody = result.andReturn().getResponse().getContentAsString(); + logger.debug("테스트 : " + responseBody); + + // then + result.andExpect(MockMvcResultMatchers.jsonPath("$.success").value("false")); + result.andExpect(MockMvcResultMatchers.jsonPath("$.error.status").value(400)); + result.andExpect(MockMvcResultMatchers.jsonPath("$.error.message").value("잘못된 결제 정보입니다.")); + } +} diff --git a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/quotation/QuotationRestControllerTest.java b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/quotation/QuotationRestControllerTest.java index 8e2c88d7..2d01f780 100644 --- a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/quotation/QuotationRestControllerTest.java +++ b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/quotation/QuotationRestControllerTest.java @@ -61,7 +61,7 @@ void beforeEach() { @Test void post_quotations_success() throws Exception { // given - Long matchId = 1L; + Long matchId = 6L; QuotationRequest.Add request = new QuotationRequest.Add( "my wedding", 1500000L, @@ -224,7 +224,7 @@ void post_quotations_fail_emptyPrice() throws Exception { @Test void get_quotations_success() throws Exception { // given - Long matchId = 1L; + Long matchId = 6L; // when ResultActions resultActions = mvc.perform( @@ -371,7 +371,7 @@ void post_quotationsConfirm_fail_permissionDenied() throws Exception { @WithUserDetails("couple@gmail.com") public void match_confirm_all_success_test() throws Exception { //given - Long matchId = 1L; + Long matchId = 6L; //when ResultActions result = mvc.perform( diff --git a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/CoupleJPARepositoryTest.java b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/CoupleJPARepositoryTest.java index eea65a34..8871363a 100644 --- a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/CoupleJPARepositoryTest.java +++ b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/CoupleJPARepositoryTest.java @@ -4,7 +4,6 @@ import com.kakao.sunsuwedding.user.couple.Couple; import com.kakao.sunsuwedding.user.couple.CoupleJPARepository; import jakarta.persistence.EntityManager; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -24,35 +23,40 @@ public class CoupleJPARepositoryTest extends DummyEntity { @Autowired private EntityManager em; + private Long id; + @BeforeEach public void setUp(){ - coupleJPARepository.save(newCouple("ssar")); + id = coupleJPARepository.save(newCouple("ssar")).getId(); em.clear(); } - @AfterEach - void afterEach() { - em.createNativeQuery("ALTER TABLE user_tb ALTER COLUMN `id` RESTART WITH 1") - .executeUpdate(); - } - @DisplayName("사용자 id로 찾기 - 성공") @Test public void findById_success_test() { - // given - Long userId = 1L; - // when - Couple couple = coupleJPARepository.findById(userId).orElseThrow( + Couple couple = coupleJPARepository.findById(id).orElseThrow( () -> new RuntimeException("해당 사용자를 찾을 수 없습니다.") ); // then (상태 검사) - assertThat(couple.getId()).isEqualTo(1); assertThat(couple.getEmail()).isEqualTo("ssar@nate.com"); assertThat(couple.getPassword()).isEqualTo("couple1234!"); - assertThat(couple.getUsername()).isEqualTo("couple"); + assertThat(couple.getUsername()).isEqualTo("ssar"); assertThat(couple.getGrade().getGradeName()).isEqualTo("normal"); } + @DisplayName("사용자 저장하기") + @Test + public void saveCouple_success_test() { + // when + Couple c1 = newCouple("newCouple"); + Couple couple = coupleJPARepository.save(c1); + + // then (상태 검사) + assertThat(couple.getEmail()).isEqualTo("newCouple@nate.com"); + assertThat(couple.getPassword()).isEqualTo("couple1234!"); + assertThat(couple.getUsername()).isEqualTo("newCouple"); + assertThat(couple.getGrade().getGradeName()).isEqualTo("normal"); + } } diff --git a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/PlannerJPARepositoryTest.java b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/PlannerJPARepositoryTest.java index 7f4e16f4..73248dd5 100644 --- a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/PlannerJPARepositoryTest.java +++ b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/PlannerJPARepositoryTest.java @@ -4,7 +4,6 @@ import com.kakao.sunsuwedding.user.planner.Planner; import com.kakao.sunsuwedding.user.planner.PlannerJPARepository; import jakarta.persistence.EntityManager; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -24,33 +23,40 @@ public class PlannerJPARepositoryTest extends DummyEntity { @Autowired private EntityManager em; + private Long id; + @BeforeEach public void setUp(){ - plannerJPARepository.save(newPlanner("ssar")); + id = plannerJPARepository.save(newPlanner("ssar")).getId(); em.clear(); } - @AfterEach - void afterEach() { - em.createNativeQuery("ALTER TABLE user_tb ALTER COLUMN `id` RESTART WITH 1") - .executeUpdate(); - } @DisplayName("사용자 id로 찾기 - 성공") @Test public void findById_success_test() { - // given - Long userId = 1L; - // when - Planner planner = plannerJPARepository.findById(userId).orElseThrow( + Planner planner = plannerJPARepository.findById(id).orElseThrow( () -> new RuntimeException("해당 플래너를 찾을 수 없습니다.") ); // then (상태 검사) - assertThat(planner.getId()).isEqualTo(1); assertThat(planner.getEmail()).isEqualTo("ssar@nate.com"); assertThat(planner.getPassword()).isEqualTo("planner1234!"); - assertThat(planner.getUsername()).isEqualTo("planner"); + assertThat(planner.getUsername()).isEqualTo("ssar"); + assertThat(planner.getGrade().getGradeName()).isEqualTo("normal"); + } + + @DisplayName("사용자 저장하기") + @Test + public void savePlanner_success_test() { + // when + Planner p1 = newPlanner("newPlanner"); + Planner planner = plannerJPARepository.save(p1); + + // then (상태 검사) + assertThat(planner.getEmail()).isEqualTo("newPlanner@nate.com"); + assertThat(planner.getPassword()).isEqualTo("planner1234!"); + assertThat(planner.getUsername()).isEqualTo("newPlanner"); assertThat(planner.getGrade().getGradeName()).isEqualTo("normal"); } diff --git a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/TokenJPARepositoryTest.java b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/TokenJPARepositoryTest.java new file mode 100644 index 00000000..9dd098ef --- /dev/null +++ b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/TokenJPARepositoryTest.java @@ -0,0 +1,83 @@ +package com.kakao.sunsuwedding.user; + +import com.kakao.sunsuwedding._core.DummyEntity; +import com.kakao.sunsuwedding.user.base_user.User; +import com.kakao.sunsuwedding.user.base_user.UserJPARepository; +import com.kakao.sunsuwedding.user.couple.Couple; +import com.kakao.sunsuwedding.user.couple.CoupleJPARepository; +import com.kakao.sunsuwedding.user.planner.Planner; +import com.kakao.sunsuwedding.user.token.Token; +import com.kakao.sunsuwedding.user.token.TokenJPARepository; +import jakarta.persistence.EntityManager; +import org.junit.jupiter.api.BeforeEach; +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.orm.jpa.AutoConfigureDataJpa; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +import static org.assertj.core.api.Assertions.assertThat; + +@AutoConfigureDataJpa +@DataJpaTest +public class TokenJPARepositoryTest extends DummyEntity { + + @Autowired + private TokenJPARepository tokenJPARepository; + + @Autowired + private UserJPARepository userJPARepository; + + @Autowired + private EntityManager em; + + private Long id; + private Long userId; + + @BeforeEach + public void setUp(){ + User user = userJPARepository.save(newPlanner("asdf")); + userId = user.getId(); + id = tokenJPARepository.save(newToken(user)).getId(); + em.clear(); + } + + @DisplayName("사용자 id로 토큰 찾기 - 성공") + @Test + public void findByUserId_success_test() { + // when + Token token = tokenJPARepository.findByUserId(userId).orElseThrow( + () -> new RuntimeException("해당 사용자의 토큰을 찾을 수 없습니다.") + ); + + // then (상태 검사) + assertThat(token.getAccessToken()).isEqualTo("accessToken"); + assertThat(token.getRefreshToken()).isEqualTo("refreshToken"); + } + + @DisplayName("토큰 저장하기 - 성공") + @Test + public void saveToken_success_test() { + // when + Couple couple = newCouple("qwer"); + Token token = tokenJPARepository.save(newToken(couple)); + + // then (상태 검사) + assertThat(token.getId()).isEqualTo(2); + assertThat(token.getAccessToken()).isEqualTo("accessToken"); + assertThat(token.getRefreshToken()).isEqualTo("refreshToken"); + } + @DisplayName("토큰 삭제하기- 성공") + @Test + public void deleteToken_success_test() { + // when + long previous_counts = tokenJPARepository.count(); + Token token = tokenJPARepository.findById(id).orElseThrow( + () -> new RuntimeException("해당 사용자의 토큰을 찾을 수 없습니다.") + ); + tokenJPARepository.delete(token); + + // then (상태 검사) + assertThat(tokenJPARepository.count()).isEqualTo(previous_counts-1); + } +} diff --git a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/UserJPARepositoryTest.java b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/UserJPARepositoryTest.java index 5317ca7f..023036f1 100644 --- a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/UserJPARepositoryTest.java +++ b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/UserJPARepositoryTest.java @@ -26,32 +26,94 @@ public class UserJPARepositoryTest extends DummyEntity { @Autowired private EntityManager em; + private Long id1; + private Long id2; + private Long id3; + @BeforeEach public void setUp(){ - userJPARepository.save(newCouple("zxcv")); + id1 = userJPARepository.save(newCouple("asdf")).getId(); + id2 = userJPARepository.save(newPlanner("qwer")).getId(); + id3 = userJPARepository.save(unActivePlanner("zxcv")).getId(); em.clear(); } - @AfterEach - void afterEach() { - em.createNativeQuery("ALTER TABLE user_tb ALTER COLUMN `id` RESTART WITH 1") - .executeUpdate(); + + @DisplayName("커플 id로 찾기 - 성공") + @Test + public void findCoupleById_success_test() { + + // when + User user = userJPARepository.findById(id1).orElseThrow( + () -> new RuntimeException("해당 유저를 찾을 수 없습니다.") + ); + + // then (상태 검사) + assertThat(user.getEmail()).isEqualTo("asdf@nate.com"); + assertThat(user.getPassword()).isEqualTo("couple1234!"); + assertThat(user.getUsername()).isEqualTo("asdf"); + assertThat(user.getDtype()).isEqualTo("couple"); + assertThat(user.isActive()).isEqualTo(true); + assertThat(user.getGrade().getGradeName()).isEqualTo("normal"); } - @DisplayName("사용자 id로 찾기 - 성공") + @DisplayName("플래너 id로 찾기 - 성공") @Test - public void findById_success_test() { - // given - Long userId = 1L; + public void findPlannerById_success_test() { + // when - User user = userJPARepository.findById(userId).orElseThrow( + User user = userJPARepository.findById(id2).orElseThrow( + () -> new RuntimeException("해당 유저를 찾을 수 없습니다.") + ); + + // then (상태 검사) + assertThat(user.getEmail()).isEqualTo("qwer@nate.com"); + assertThat(user.getPassword()).isEqualTo("planner1234!"); + assertThat(user.getUsername()).isEqualTo("qwer"); + assertThat(user.getDtype()).isEqualTo("planner"); + assertThat(user.isActive()).isEqualTo(true); + assertThat(user.getGrade().getGradeName()).isEqualTo("normal"); + } + @DisplayName("삭제된 유저 id로 찾기 - 성공") + @Test + public void findUnactiveUserById_success_test() { + + // when + User user = userJPARepository.findByEmailNative("zxcv@nate.com").orElseThrow( () -> new RuntimeException("해당 유저를 찾을 수 없습니다.") ); // then (상태 검사) - assertThat(user.getId()).isEqualTo(1); assertThat(user.getEmail()).isEqualTo("zxcv@nate.com"); + assertThat(user.getPassword()).isEqualTo("planner1234!"); + assertThat(user.getUsername()).isEqualTo("zxcv"); + assertThat(user.getDtype()).isEqualTo("planner"); + assertThat(user.isActive()).isEqualTo(false); + assertThat(user.getGrade().getGradeName()).isEqualTo("normal"); + } + + @DisplayName("사용자 저장 - 성공") + @Test + public void saveUser_success_test() { + + // when + Couple c1 = newCouple("newCouple"); + User user = userJPARepository.save(c1); + + // then (상태 검사) + assertThat(user.getEmail()).isEqualTo("newCouple@nate.com"); assertThat(user.getPassword()).isEqualTo("couple1234!"); - assertThat(user.getUsername()).isEqualTo("couple"); + assertThat(user.getUsername()).isEqualTo("newCouple"); assertThat(user.getGrade().getGradeName()).isEqualTo("normal"); } + @DisplayName("사용자 삭제 - 성공") + @Test + public void deleteUser_success_test() { + + long previous_counts = userJPARepository.count(); + // when + userJPARepository.deleteById(id1); + + // then (상태 검사) + assertThat(userJPARepository.count()).isEqualTo(previous_counts - 1); + } } diff --git a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/UserRestControllerTest.java b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/UserRestControllerTest.java index b00d4d07..c5594b71 100644 --- a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/UserRestControllerTest.java +++ b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/UserRestControllerTest.java @@ -13,6 +13,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithUserDetails; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.jdbc.Sql; import org.springframework.test.web.servlet.MockMvc; @@ -32,7 +33,6 @@ public class UserRestControllerTest { private static final Logger logger = LoggerFactory.getLogger(UserRestControllerTest.class); - private CustomUserDetailsService customUserDetailsService; @Autowired private MockMvc mvc; @@ -205,9 +205,8 @@ public void user_login_fail_wrong_password_test() throws Exception { result.andExpect(jsonPath("$.error.message").value("패스워드를 잘못 입력하셨습니다")); } - /* // ============ 회원 탈퇴 테스트 ============ - /* + @DisplayName("회원 탈퇴 성공 테스트") @Test @WithUserDetails("couple@gmail.com") @@ -216,8 +215,7 @@ public void user_withdraw_success_test() throws Exception { // when ResultActions result = mvc.perform( - MockMvcRequestBuilders - .delete("/user") + MockMvcRequestBuilders.delete("/user") ); String responseBody = result.andReturn().getResponse().getContentAsString(); logger.debug("테스트 : " + responseBody); @@ -225,5 +223,35 @@ public void user_withdraw_success_test() throws Exception { // then result.andExpect(MockMvcResultMatchers.jsonPath("$.success").value("true")); } - */ + + // ============ 유저 정보 조회 ============ + @DisplayName("유저 정보 조회 성공") + @Test + @WithUserDetails("planner@gmail.com") + void get_user_info_success_test() throws Exception { + // when + ResultActions resultActions = mvc.perform( + MockMvcRequestBuilders + .get("/user/info") + ); + // then + resultActions.andExpect(jsonPath("$.success").value("true")); + resultActions.andExpect(jsonPath("$.response.username").value("planner")); + resultActions.andExpect(jsonPath("$.response.email").value("planner@gmail.com")); + resultActions.andExpect(jsonPath("$.response.role").value("planner")); + resultActions.andExpect(jsonPath("$.response.grade").value("normal")); + } + // ============ 유저 토큰 갱신 ============ + @DisplayName("유저 토큰 refresh 성공") + @Test + @WithUserDetails("planner@gmail.com") + void user_token_refresh_success_test() throws Exception { + // when + ResultActions resultActions = mvc.perform( + MockMvcRequestBuilders + .put("/user/token") + ); + // then + resultActions.andExpect(jsonPath("$.success").value("true")); + } } diff --git a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/RoleTest.java b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/util/RoleTest.java similarity index 96% rename from sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/RoleTest.java rename to sunsu-wedding/src/test/java/com/kakao/sunsuwedding/util/RoleTest.java index a5e31d78..5c340066 100644 --- a/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/user/RoleTest.java +++ b/sunsu-wedding/src/test/java/com/kakao/sunsuwedding/util/RoleTest.java @@ -1,4 +1,4 @@ -package com.kakao.sunsuwedding.user; +package com.kakao.sunsuwedding.util; import com.kakao.sunsuwedding._core.errors.exception.BadRequestException; import com.kakao.sunsuwedding.user.constant.Role;