From 693dd2a1d4992106613e9ebe1f850203da18fbc0 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 04:38:06 +0900 Subject: [PATCH 01/26] =?UTF-8?q?feat:=20user=20=ED=9A=8C=EC=9B=90?= =?UTF-8?q?=EA=B0=80=EC=9E=85=20=EC=8B=9C=20email=20=ED=95=84=EB=93=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/backendoori/ootw/user/dto/SignupDto.java | 3 +-- .../java/com/backendoori/ootw/user/service/UserService.java | 1 - .../com/backendoori/ootw/post/service/PostServiceTest.java | 3 --- .../backendoori/ootw/user/controller/UserControllerTest.java | 2 +- .../com/backendoori/ootw/user/service/UserServiceTest.java | 2 +- 5 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java b/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java index fea29628..956f35ed 100644 --- a/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java +++ b/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java @@ -3,8 +3,7 @@ public record SignupDto( String email, String password, - String nickname, - String image + String nickname ) { } diff --git a/src/main/java/com/backendoori/ootw/user/service/UserService.java b/src/main/java/com/backendoori/ootw/user/service/UserService.java index 72707bc9..52c655c4 100644 --- a/src/main/java/com/backendoori/ootw/user/service/UserService.java +++ b/src/main/java/com/backendoori/ootw/user/service/UserService.java @@ -36,7 +36,6 @@ public UserDto signup(SignupDto signupDto) { .email(signupDto.email()) .password(passwordEncoder.encode(signupDto.password())) .nickname(signupDto.nickname()) - .image(signupDto.image()) .build(); userRepository.save(user); diff --git a/src/test/java/com/backendoori/ootw/post/service/PostServiceTest.java b/src/test/java/com/backendoori/ootw/post/service/PostServiceTest.java index 028d19b4..3f8aff68 100644 --- a/src/test/java/com/backendoori/ootw/post/service/PostServiceTest.java +++ b/src/test/java/com/backendoori/ootw/post/service/PostServiceTest.java @@ -109,9 +109,6 @@ void saveFailUserNotFound() { // given setAuthentication(user.getId() + 1); - System.out.println(user.getId() + 1); - System.out.println(userRepository.findAll().stream().map(User::getId).toList()); - WeatherDto weatherDto = new WeatherDto(0.0, -10.0, 10.0, 1, 1); PostSaveRequest postSaveRequest = diff --git a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java index a7e42092..46ce8f2e 100644 --- a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java +++ b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java @@ -170,7 +170,7 @@ private SignupDto generateSignupDto() { String nickname = faker.internet().username(); String image = faker.internet().url(); - return new SignupDto(email, password, nickname, image); + return new SignupDto(email, password, nickname); } private UserDto createUser(SignupDto signupDto) { diff --git a/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java b/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java index 7f36f59f..b6ae5b97 100644 --- a/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java +++ b/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java @@ -140,7 +140,7 @@ private SignupDto generateSignupDto() { String nickname = faker.internet().username(); String image = faker.internet().url(); - return new SignupDto(email, password, nickname, image); + return new SignupDto(email, password, nickname); } private User generateUser(String password) { From 7679024f1a36e8a9b7b03ecacbaf35e3b78262e6 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:20:48 +0900 Subject: [PATCH 02/26] =?UTF-8?q?feat:=20assert=20util=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backendoori/ootw/common/AssertUtil.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/main/java/com/backendoori/ootw/common/AssertUtil.java diff --git a/src/main/java/com/backendoori/ootw/common/AssertUtil.java b/src/main/java/com/backendoori/ootw/common/AssertUtil.java new file mode 100644 index 00000000..e083b4e2 --- /dev/null +++ b/src/main/java/com/backendoori/ootw/common/AssertUtil.java @@ -0,0 +1,33 @@ +package com.backendoori.ootw.common; + +import java.util.Objects; +import java.util.function.Supplier; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class AssertUtil extends Assert { + + public static void notBlank(@Nullable String string, String message) { + if (string == null || string.isBlank()) { + throw new IllegalArgumentException(message); + } + } + + public static void hasPattern(@Nullable String string, @Nullable String pattern, String message) { + notNull(string, message); + + if (!string.matches(Objects.requireNonNull(pattern))) { + throw new IllegalArgumentException(message); + } + } + + public static void throwIf(boolean state, Supplier exceptionSupplier) { + if (state) { + throw exceptionSupplier.get(); + } + } + +} From 6d8f183e9ac1118237fdb1df4bfe17f9d7d7af17 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:21:22 +0900 Subject: [PATCH 03/26] =?UTF-8?q?feat:=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20?= =?UTF-8?q?=ED=98=95=EC=8B=9D=EC=9D=84=20=EC=A0=80=EC=9E=A5=ED=95=9C=20?= =?UTF-8?q?=EC=83=81=EC=88=98=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backendoori/ootw/user/validation/RFC5322.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/main/java/com/backendoori/ootw/user/validation/RFC5322.java diff --git a/src/main/java/com/backendoori/ootw/user/validation/RFC5322.java b/src/main/java/com/backendoori/ootw/user/validation/RFC5322.java new file mode 100644 index 00000000..8e44b1ec --- /dev/null +++ b/src/main/java/com/backendoori/ootw/user/validation/RFC5322.java @@ -0,0 +1,12 @@ +package com.backendoori.ootw.user.validation; + +import java.util.regex.Pattern; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class RFC5322 { + + public static final String REGEX = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$"; + +} From 59dcee680815f05c0dc0f0c42dae62145b6295d2 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:22:13 +0900 Subject: [PATCH 04/26] =?UTF-8?q?feat:=20dto=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20annotation=EA=B3=BC=20validator=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 메시지를 담은 상수 클래스도 추가 --- .../ootw/user/validation/Message.java | 18 ++++++++++ .../ootw/user/validation/Password.java | 23 ++++++++++++ .../user/validation/PasswordValidator.java | 35 +++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 src/main/java/com/backendoori/ootw/user/validation/Message.java create mode 100644 src/main/java/com/backendoori/ootw/user/validation/Password.java create mode 100644 src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java diff --git a/src/main/java/com/backendoori/ootw/user/validation/Message.java b/src/main/java/com/backendoori/ootw/user/validation/Message.java new file mode 100644 index 00000000..04bf0676 --- /dev/null +++ b/src/main/java/com/backendoori/ootw/user/validation/Message.java @@ -0,0 +1,18 @@ +package com.backendoori.ootw.user.validation; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class Message { + + public static final String INVALID_EMAIL = "이메일 형식이 올바르지 않습니다."; + + public static final String INVALID_PASSWORD = "비밀번호는 숫자, 영문자, 특수문자를 포함한 " + + PasswordValidator.MIN_SIZE + "자 이상, " + + PasswordValidator.MAX_SIZE + "자 이내의 문자여야 합니다."; + + public static final String BLANK_PASSWORD = "비밀번호는 공백일 수 없습니다."; + public static final String BLANK_NICKNAME = "닉네임은 공백일 수 없습니다."; + +} diff --git a/src/main/java/com/backendoori/ootw/user/validation/Password.java b/src/main/java/com/backendoori/ootw/user/validation/Password.java new file mode 100644 index 00000000..f3a0c02a --- /dev/null +++ b/src/main/java/com/backendoori/ootw/user/validation/Password.java @@ -0,0 +1,23 @@ +package com.backendoori.ootw.user.validation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +@Documented +@Constraint(validatedBy = PasswordValidator.class) +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Password { + + String message() default Message.INVALID_PASSWORD; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java b/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java new file mode 100644 index 00000000..2cdf2fb8 --- /dev/null +++ b/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java @@ -0,0 +1,35 @@ +package com.backendoori.ootw.user.validation; + +import java.util.Objects; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +public class PasswordValidator implements ConstraintValidator { + + public static final int MIN_SIZE = 8; + public static final int MAX_SIZE = 30; + public static final String PATTERN = "^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[$@$!%%*#?&])[A-Za-z[0-9]$@$!%%*#?&]" + + "{" + MIN_SIZE + "," + MAX_SIZE + "}$"; + + @Override + public boolean isValid(String password, ConstraintValidatorContext context) { + if (Objects.isNull(password) || password.isBlank()) { + return violateWithMessage(context, Message.BLANK_PASSWORD); + } + + if (!password.matches(PATTERN)) { + return violateWithMessage(context, Message.INVALID_PASSWORD); + } + + return true; + } + + private boolean violateWithMessage(ConstraintValidatorContext context, String message) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(message) + .addConstraintViolation(); + + return false; + } + +} From 9286e2bf6176f01a5278efcd237d547494cfe05a Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:23:14 +0900 Subject: [PATCH 05/26] =?UTF-8?q?feat:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20dto=EC=97=90=20validation=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/backendoori/ootw/user/dto/SignupDto.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java b/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java index 956f35ed..f53c5008 100644 --- a/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java +++ b/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java @@ -1,8 +1,23 @@ package com.backendoori.ootw.user.dto; +import com.backendoori.ootw.user.validation.Message; +import com.backendoori.ootw.user.validation.Password; +import com.backendoori.ootw.user.validation.RFC5322; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + public record SignupDto( + @NotNull + @Email(regexp = RFC5322.REGEX) String email, + + @NotNull + @Password String password, + + @NotNull + @NotBlank(message = Message.BLANK_NICKNAME) String nickname ) { From b2f4dad4bcdc2550c4972660158a93e703b783f8 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:23:34 +0900 Subject: [PATCH 06/26] =?UTF-8?q?feat:=20user=20entity=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=8B=9C=20validation=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/backendoori/ootw/user/domain/User.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/user/domain/User.java b/src/main/java/com/backendoori/ootw/user/domain/User.java index 6fdecfff..a50d51ed 100644 --- a/src/main/java/com/backendoori/ootw/user/domain/User.java +++ b/src/main/java/com/backendoori/ootw/user/domain/User.java @@ -1,6 +1,9 @@ package com.backendoori.ootw.user.domain; +import com.backendoori.ootw.common.AssertUtil; import com.backendoori.ootw.common.BaseEntity; +import com.backendoori.ootw.user.validation.Message; +import com.backendoori.ootw.user.validation.RFC5322; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -8,7 +11,6 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; import lombok.AccessLevel; -import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -18,7 +20,6 @@ @Getter @Builder @NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor(access = AccessLevel.PROTECTED) public class User extends BaseEntity { @Id @@ -38,4 +39,16 @@ public class User extends BaseEntity { @Column(name = "image") private String image; + public User(Long id, String email, String password, String nickname, String image) { + AssertUtil.hasPattern(email, RFC5322.REGEX, Message.INVALID_EMAIL); + AssertUtil.notBlank(password,Message.BLANK_PASSWORD); + AssertUtil.notBlank(nickname, Message.BLANK_NICKNAME); + + this.id = id; + this.email = email; + this.password = password; + this.nickname = nickname; + this.image = image; + } + } From fb86531ad414eb694c8a20b866ac7d4d183691b6 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:24:17 +0900 Subject: [PATCH 07/26] =?UTF-8?q?feat:=20service=EC=97=90=EC=84=9C=20user?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20=EC=8B=9C=20password=20=ED=98=95?= =?UTF-8?q?=EC=8B=9D=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/user/service/UserService.java | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/user/service/UserService.java b/src/main/java/com/backendoori/ootw/user/service/UserService.java index 52c655c4..747143e0 100644 --- a/src/main/java/com/backendoori/ootw/user/service/UserService.java +++ b/src/main/java/com/backendoori/ootw/user/service/UserService.java @@ -1,5 +1,7 @@ package com.backendoori.ootw.user.service; +import java.util.Objects; +import com.backendoori.ootw.common.AssertUtil; import com.backendoori.ootw.exception.AlreadyExistEmailException; import com.backendoori.ootw.exception.IncorrectPasswordException; import com.backendoori.ootw.exception.UserNotFoundException; @@ -10,6 +12,9 @@ import com.backendoori.ootw.user.dto.TokenDto; import com.backendoori.ootw.user.dto.UserDto; import com.backendoori.ootw.user.repository.UserRepository; +import com.backendoori.ootw.user.validation.Message; +import com.backendoori.ootw.user.validation.PasswordValidator; +import com.backendoori.ootw.user.validation.RFC5322; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @@ -28,15 +33,10 @@ public UserDto signup(SignupDto signupDto) { boolean isAlreadyExistEmail = userRepository.findByEmail(signupDto.email()) .isPresent(); - if (isAlreadyExistEmail) { - throw new AlreadyExistEmailException(); - } + AssertUtil.throwIf(isAlreadyExistEmail, AlreadyExistEmailException::new); + AssertUtil.isTrue(isValidPassword(signupDto.password()), Message.INVALID_PASSWORD); - User user = User.builder() - .email(signupDto.email()) - .password(passwordEncoder.encode(signupDto.password())) - .nickname(signupDto.nickname()) - .build(); + User user = buildUser(signupDto); userRepository.save(user); @@ -46,14 +46,29 @@ public UserDto signup(SignupDto signupDto) { public TokenDto login(LoginDto loginDto) { User user = userRepository.findByEmail(loginDto.email()) .orElseThrow(UserNotFoundException::new); + boolean isIncorrectPassword = !matchPassword(loginDto.password(), user.getPassword()); - if (!passwordEncoder.matches(loginDto.password(), user.getPassword())) { - throw new IncorrectPasswordException(); - } + AssertUtil.throwIf(isIncorrectPassword, IncorrectPasswordException::new); String token = tokenProvider.createToken(user.getId()); return new TokenDto(token); } + private User buildUser(SignupDto signupDto) { + return User.builder() + .email(signupDto.email()) + .password(passwordEncoder.encode(signupDto.password())) + .nickname(signupDto.nickname()) + .build(); + } + + private boolean matchPassword(String decrypted, String encrypted) { + return passwordEncoder.matches(decrypted, encrypted); + } + + private boolean isValidPassword(String password) { + return Objects.nonNull(password) && password.matches(PasswordValidator.PATTERN); + } + } From 9e1cc983a6da6335fb31edbce894555af0644653 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:24:46 +0900 Subject: [PATCH 08/26] =?UTF-8?q?test:=20user=20entity=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/user/domain/UserTest.java | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 src/test/java/com/backendoori/ootw/user/domain/UserTest.java diff --git a/src/test/java/com/backendoori/ootw/user/domain/UserTest.java b/src/test/java/com/backendoori/ootw/user/domain/UserTest.java new file mode 100644 index 00000000..2d3bbdba --- /dev/null +++ b/src/test/java/com/backendoori/ootw/user/domain/UserTest.java @@ -0,0 +1,120 @@ +package com.backendoori.ootw.user.domain; + +import static org.assertj.core.api.Assertions.assertThatException; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNoException; + +import java.util.stream.Stream; +import com.backendoori.ootw.user.validation.Message; +import net.datafaker.Faker; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.NullAndEmptySource; + +class UserTest { + + static final Faker faker = new Faker(); + + Long id; + String email; + String password; + String nickname; + String image; + + @BeforeEach + void setup() { + id = (long) faker.number().positive(); + email = faker.internet().emailAddress(); + password = faker.internet().password(); + nickname = faker.internet().username(); + image = faker.internet().url(); + } + + @DisplayName("instance 생성에 성공한다.") + @Test + void testCreate() { + // given + + // when + ThrowingCallable createUser = this::buildUser; + + // then + assertThatNoException().isThrownBy(createUser); + } + + @DisplayName("잘못된 형식의 이메일인 경우 생성에 실패한다.") + @NullAndEmptySource + @MethodSource("generateInvalidEmails") + @ParameterizedTest() + void testCreateInvalidEmail(String email) { + // given + this.email = email; + + // when + ThrowingCallable createUser = this::buildUser; + + // then + assertThatIllegalArgumentException() + .isThrownBy(createUser) + .withMessage(Message.INVALID_EMAIL); + } + + @DisplayName("비밀번호가 공백인 경우 생성에 실패한다.") + @NullAndEmptySource + @ParameterizedTest + void testCreateBlankPassword(String password) { + // given + this.password = password; + + // when + ThrowingCallable createUser = this::buildUser; + + // then + assertThatIllegalArgumentException() + .isThrownBy(createUser) + .withMessage(Message.BLANK_PASSWORD); + } + + @DisplayName("닉네임이 공백인 경우 생성에 실패한다.") + @NullAndEmptySource + @ParameterizedTest + void testCreateBlankNickName(String nickname) { + // given + this.nickname = nickname; + + // when + ThrowingCallable createUser = this::buildUser; + + // then + assertThatIllegalArgumentException() + .isThrownBy(createUser) + .withMessage(Message.BLANK_NICKNAME); + } + + private static Stream generateInvalidEmails() { + return Stream.of( + Arguments.of(faker.app().name()), + Arguments.of(faker.name().fullName()), + Arguments.of(faker.internet().url()), + Arguments.of(faker.internet().domainName()), + Arguments.of(faker.internet().webdomain()), + Arguments.of(faker.internet().botUserAgentAny()) + ); + } + + private User buildUser() { + return User.builder() + .id(id) + .email(email) + .password(password) + .nickname(nickname) + .image(image) + .build(); + } + +} From 9acff2b591b776a0f38d8392e5eda1cba9d90cdd Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:49:17 +0900 Subject: [PATCH 09/26] =?UTF-8?q?refactor:=20exception=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{ => user}/exception/AlreadyExistEmailException.java | 2 +- .../{ => user}/exception/IncorrectPasswordException.java | 2 +- .../com/backendoori/ootw/user/service/UserService.java | 5 ++--- .../ootw/user/controller/UserControllerTest.java | 4 ++-- .../com/backendoori/ootw/user/service/UserServiceTest.java | 7 +++---- 5 files changed, 9 insertions(+), 11 deletions(-) rename src/main/java/com/backendoori/ootw/{ => user}/exception/AlreadyExistEmailException.java (87%) rename src/main/java/com/backendoori/ootw/{ => user}/exception/IncorrectPasswordException.java (87%) diff --git a/src/main/java/com/backendoori/ootw/exception/AlreadyExistEmailException.java b/src/main/java/com/backendoori/ootw/user/exception/AlreadyExistEmailException.java similarity index 87% rename from src/main/java/com/backendoori/ootw/exception/AlreadyExistEmailException.java rename to src/main/java/com/backendoori/ootw/user/exception/AlreadyExistEmailException.java index 16ae8ab6..d8ec3ae4 100644 --- a/src/main/java/com/backendoori/ootw/exception/AlreadyExistEmailException.java +++ b/src/main/java/com/backendoori/ootw/user/exception/AlreadyExistEmailException.java @@ -1,4 +1,4 @@ -package com.backendoori.ootw.exception; +package com.backendoori.ootw.user.exception; import org.springframework.dao.DuplicateKeyException; diff --git a/src/main/java/com/backendoori/ootw/exception/IncorrectPasswordException.java b/src/main/java/com/backendoori/ootw/user/exception/IncorrectPasswordException.java similarity index 87% rename from src/main/java/com/backendoori/ootw/exception/IncorrectPasswordException.java rename to src/main/java/com/backendoori/ootw/user/exception/IncorrectPasswordException.java index cea57a9b..474f996e 100644 --- a/src/main/java/com/backendoori/ootw/exception/IncorrectPasswordException.java +++ b/src/main/java/com/backendoori/ootw/user/exception/IncorrectPasswordException.java @@ -1,4 +1,4 @@ -package com.backendoori.ootw.exception; +package com.backendoori.ootw.user.exception; import org.springframework.security.core.AuthenticationException; diff --git a/src/main/java/com/backendoori/ootw/user/service/UserService.java b/src/main/java/com/backendoori/ootw/user/service/UserService.java index 747143e0..e3c77242 100644 --- a/src/main/java/com/backendoori/ootw/user/service/UserService.java +++ b/src/main/java/com/backendoori/ootw/user/service/UserService.java @@ -2,8 +2,8 @@ import java.util.Objects; import com.backendoori.ootw.common.AssertUtil; -import com.backendoori.ootw.exception.AlreadyExistEmailException; -import com.backendoori.ootw.exception.IncorrectPasswordException; +import com.backendoori.ootw.user.exception.AlreadyExistEmailException; +import com.backendoori.ootw.user.exception.IncorrectPasswordException; import com.backendoori.ootw.exception.UserNotFoundException; import com.backendoori.ootw.security.jwt.TokenProvider; import com.backendoori.ootw.user.domain.User; @@ -14,7 +14,6 @@ import com.backendoori.ootw.user.repository.UserRepository; import com.backendoori.ootw.user.validation.Message; import com.backendoori.ootw.user.validation.PasswordValidator; -import com.backendoori.ootw.user.validation.RFC5322; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; diff --git a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java index 46ce8f2e..012612d2 100644 --- a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java +++ b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java @@ -10,8 +10,8 @@ import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; -import com.backendoori.ootw.exception.AlreadyExistEmailException; -import com.backendoori.ootw.exception.IncorrectPasswordException; +import com.backendoori.ootw.user.exception.AlreadyExistEmailException; +import com.backendoori.ootw.user.exception.IncorrectPasswordException; import com.backendoori.ootw.exception.UserNotFoundException; import com.backendoori.ootw.security.jwt.TokenProvider; import com.backendoori.ootw.user.dto.LoginDto; diff --git a/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java b/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java index b6ae5b97..da05966e 100644 --- a/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java +++ b/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java @@ -4,8 +4,8 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatNoException; -import com.backendoori.ootw.exception.AlreadyExistEmailException; -import com.backendoori.ootw.exception.IncorrectPasswordException; +import com.backendoori.ootw.user.exception.AlreadyExistEmailException; +import com.backendoori.ootw.user.exception.IncorrectPasswordException; import com.backendoori.ootw.exception.UserNotFoundException; import com.backendoori.ootw.user.domain.User; import com.backendoori.ootw.user.dto.LoginDto; @@ -136,9 +136,8 @@ void failIncorrectPassword() { private SignupDto generateSignupDto() { String email = faker.internet().emailAddress(); - String password = faker.internet().password(); + String password = faker.internet().password(8, 30, true, true, true); String nickname = faker.internet().username(); - String image = faker.internet().url(); return new SignupDto(email, password, nickname); } From 98a4d1e02a34d54c28615cae5029dbe2ba48b7f6 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:49:36 +0900 Subject: [PATCH 10/26] =?UTF-8?q?style:=20=ED=95=84=EC=9A=94=EC=97=86?= =?UTF-8?q?=EB=8A=94=20import=20=EB=AC=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/backendoori/ootw/user/validation/RFC5322.java | 1 - src/test/java/com/backendoori/ootw/user/domain/UserTest.java | 1 - 2 files changed, 2 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/user/validation/RFC5322.java b/src/main/java/com/backendoori/ootw/user/validation/RFC5322.java index 8e44b1ec..1180e8f2 100644 --- a/src/main/java/com/backendoori/ootw/user/validation/RFC5322.java +++ b/src/main/java/com/backendoori/ootw/user/validation/RFC5322.java @@ -1,6 +1,5 @@ package com.backendoori.ootw.user.validation; -import java.util.regex.Pattern; import lombok.AccessLevel; import lombok.NoArgsConstructor; diff --git a/src/test/java/com/backendoori/ootw/user/domain/UserTest.java b/src/test/java/com/backendoori/ootw/user/domain/UserTest.java index 2d3bbdba..1444316e 100644 --- a/src/test/java/com/backendoori/ootw/user/domain/UserTest.java +++ b/src/test/java/com/backendoori/ootw/user/domain/UserTest.java @@ -1,6 +1,5 @@ package com.backendoori.ootw.user.domain; -import static org.assertj.core.api.Assertions.assertThatException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatNoException; From d5881edfa0a6642befe5b5fbe5295c3fbfb21a63 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:52:48 +0900 Subject: [PATCH 11/26] =?UTF-8?q?refactor:=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EA=B4=80=EB=A0=A8=20=EC=83=81=EC=88=98=20=EC=84=A0?= =?UTF-8?q?=EC=96=B8=20=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/backendoori/ootw/user/service/UserService.java | 3 ++- .../java/com/backendoori/ootw/user/validation/Message.java | 4 ++-- .../com/backendoori/ootw/user/validation/Password.java | 5 +++++ .../ootw/user/validation/PasswordValidator.java | 7 +------ 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/user/service/UserService.java b/src/main/java/com/backendoori/ootw/user/service/UserService.java index e3c77242..d9e3b047 100644 --- a/src/main/java/com/backendoori/ootw/user/service/UserService.java +++ b/src/main/java/com/backendoori/ootw/user/service/UserService.java @@ -13,6 +13,7 @@ import com.backendoori.ootw.user.dto.UserDto; import com.backendoori.ootw.user.repository.UserRepository; import com.backendoori.ootw.user.validation.Message; +import com.backendoori.ootw.user.validation.Password; import com.backendoori.ootw.user.validation.PasswordValidator; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; @@ -67,7 +68,7 @@ private boolean matchPassword(String decrypted, String encrypted) { } private boolean isValidPassword(String password) { - return Objects.nonNull(password) && password.matches(PasswordValidator.PATTERN); + return Objects.nonNull(password) && password.matches(Password.PATTERN); } } diff --git a/src/main/java/com/backendoori/ootw/user/validation/Message.java b/src/main/java/com/backendoori/ootw/user/validation/Message.java index 04bf0676..22e4f08b 100644 --- a/src/main/java/com/backendoori/ootw/user/validation/Message.java +++ b/src/main/java/com/backendoori/ootw/user/validation/Message.java @@ -9,8 +9,8 @@ public final class Message { public static final String INVALID_EMAIL = "이메일 형식이 올바르지 않습니다."; public static final String INVALID_PASSWORD = "비밀번호는 숫자, 영문자, 특수문자를 포함한 " - + PasswordValidator.MIN_SIZE + "자 이상, " - + PasswordValidator.MAX_SIZE + "자 이내의 문자여야 합니다."; + + Password.MIN_SIZE + "자 이상, " + + Password.MAX_SIZE + "자 이내의 문자여야 합니다."; public static final String BLANK_PASSWORD = "비밀번호는 공백일 수 없습니다."; public static final String BLANK_NICKNAME = "닉네임은 공백일 수 없습니다."; diff --git a/src/main/java/com/backendoori/ootw/user/validation/Password.java b/src/main/java/com/backendoori/ootw/user/validation/Password.java index f3a0c02a..32f02ba9 100644 --- a/src/main/java/com/backendoori/ootw/user/validation/Password.java +++ b/src/main/java/com/backendoori/ootw/user/validation/Password.java @@ -14,6 +14,11 @@ @Retention(RetentionPolicy.RUNTIME) public @interface Password { + int MIN_SIZE = 8; + int MAX_SIZE = 30; + String PATTERN = "^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[$@$!%%*#?&])[A-Za-z[0-9]$@$!%%*#?&]" + + "{" + MIN_SIZE + "," + MAX_SIZE + "}$"; + String message() default Message.INVALID_PASSWORD; Class[] groups() default {}; diff --git a/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java b/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java index 2cdf2fb8..a6c07301 100644 --- a/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java +++ b/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java @@ -6,18 +6,13 @@ public class PasswordValidator implements ConstraintValidator { - public static final int MIN_SIZE = 8; - public static final int MAX_SIZE = 30; - public static final String PATTERN = "^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[$@$!%%*#?&])[A-Za-z[0-9]$@$!%%*#?&]" + - "{" + MIN_SIZE + "," + MAX_SIZE + "}$"; - @Override public boolean isValid(String password, ConstraintValidatorContext context) { if (Objects.isNull(password) || password.isBlank()) { return violateWithMessage(context, Message.BLANK_PASSWORD); } - if (!password.matches(PATTERN)) { + if (!password.matches(Password.PATTERN)) { return violateWithMessage(context, Message.INVALID_PASSWORD); } From 4bf407825eb2471317dbb7ef4c3cc6777d8ab05d Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 08:32:41 +0900 Subject: [PATCH 12/26] style: rename field --- .../java/com/backendoori/ootw/user/service/UserService.java | 4 ++-- .../java/com/backendoori/ootw/user/validation/Password.java | 2 +- .../backendoori/ootw/user/validation/PasswordValidator.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/user/service/UserService.java b/src/main/java/com/backendoori/ootw/user/service/UserService.java index d9e3b047..967aa091 100644 --- a/src/main/java/com/backendoori/ootw/user/service/UserService.java +++ b/src/main/java/com/backendoori/ootw/user/service/UserService.java @@ -14,11 +14,11 @@ import com.backendoori.ootw.user.repository.UserRepository; import com.backendoori.ootw.user.validation.Message; import com.backendoori.ootw.user.validation.Password; -import com.backendoori.ootw.user.validation.PasswordValidator; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; @Service @RequiredArgsConstructor @@ -68,7 +68,7 @@ private boolean matchPassword(String decrypted, String encrypted) { } private boolean isValidPassword(String password) { - return Objects.nonNull(password) && password.matches(Password.PATTERN); + return StringUtils.hasLength(password) && password.matches(Password.REGEX); } } diff --git a/src/main/java/com/backendoori/ootw/user/validation/Password.java b/src/main/java/com/backendoori/ootw/user/validation/Password.java index 32f02ba9..764f3095 100644 --- a/src/main/java/com/backendoori/ootw/user/validation/Password.java +++ b/src/main/java/com/backendoori/ootw/user/validation/Password.java @@ -16,7 +16,7 @@ int MIN_SIZE = 8; int MAX_SIZE = 30; - String PATTERN = "^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[$@$!%%*#?&])[A-Za-z[0-9]$@$!%%*#?&]" + + String REGEX = "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[@$!%*#?&^])[A-Za-z\\d@$!%*#?&^]" + "{" + MIN_SIZE + "," + MAX_SIZE + "}$"; String message() default Message.INVALID_PASSWORD; diff --git a/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java b/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java index a6c07301..2fb653e8 100644 --- a/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java +++ b/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java @@ -12,7 +12,7 @@ public boolean isValid(String password, ConstraintValidatorContext context) { return violateWithMessage(context, Message.BLANK_PASSWORD); } - if (!password.matches(Password.PATTERN)) { + if (!password.matches(Password.REGEX)) { return violateWithMessage(context, Message.INVALID_PASSWORD); } From bb578b2c40639932c4241e62f6e74a59fcdabd3d Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 08:32:59 +0900 Subject: [PATCH 13/26] =?UTF-8?q?test:=20user=20service=20=EB=B9=84?= =?UTF-8?q?=EB=B0=80=EB=B2=88=ED=98=B8=20=EA=B2=80=EC=A6=9D=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/user/service/UserServiceTest.java | 57 ++++++++++++++++--- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java b/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java index da05966e..401f3c7b 100644 --- a/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java +++ b/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java @@ -1,17 +1,21 @@ package com.backendoori.ootw.user.service; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatException; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatNoException; -import com.backendoori.ootw.user.exception.AlreadyExistEmailException; -import com.backendoori.ootw.user.exception.IncorrectPasswordException; +import java.util.stream.Stream; import com.backendoori.ootw.exception.UserNotFoundException; import com.backendoori.ootw.user.domain.User; import com.backendoori.ootw.user.dto.LoginDto; import com.backendoori.ootw.user.dto.SignupDto; import com.backendoori.ootw.user.dto.TokenDto; +import com.backendoori.ootw.user.exception.AlreadyExistEmailException; +import com.backendoori.ootw.user.exception.IncorrectPasswordException; import com.backendoori.ootw.user.repository.UserRepository; +import com.backendoori.ootw.user.validation.Message; import net.datafaker.Faker; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.AfterEach; @@ -21,6 +25,10 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.NullAndEmptySource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.security.crypto.password.PasswordEncoder; @@ -73,10 +81,37 @@ void failAlreadyExistUser() { ThrowingCallable signup = () -> userService.signup(signupDto); // then - assertThatExceptionOfType(AlreadyExistEmailException.class).isThrownBy(signup) + assertThatExceptionOfType(AlreadyExistEmailException.class) + .isThrownBy(signup) .withMessage(AlreadyExistEmailException.DEFAULT_MESSAGE); } + @DisplayName("비밀번호 형식이 올바르지 않을 경우 회원가입에 실패한다") + @NullAndEmptySource + @MethodSource("generateInvalidPasswords") + @ParameterizedTest + void failInvalidPassword(String password) { + // given + SignupDto signupDto = generateSignupDto(password); + + // when + ThrowingCallable signup = () -> userService.signup(signupDto); + + // then + assertThatIllegalArgumentException() + .isThrownBy(signup) + .withMessage(Message.INVALID_PASSWORD); + } + + private static Stream generateInvalidPasswords() { + return Stream.of( + faker.internet().password(1, 7, true, true, true), + faker.internet().password(31, 50, true, true, true), + faker.internet().password(8, 30, true, false, true), + faker.internet().password(8, 30, true, true, false) + ); + } + } @DisplayName("로그인 테스트") @@ -95,14 +130,15 @@ void success() { TokenDto tokenDto = userService.login(loginDto); // then - assertThat(tokenDto.token()).isInstanceOf(String.class) + assertThat(tokenDto.token()) + .isInstanceOf(String.class) .isNotNull() .isNotBlank(); } @DisplayName("email이 일치하는 사용자가 없으면 로그인에 실패한다") @Test - void failNotExistUser() { + void failUserNotFound() { // given String password = faker.internet().password(); User user = generateUser(password); @@ -112,7 +148,8 @@ void failNotExistUser() { ThrowingCallable login = () -> userService.login(loginDto); // then - assertThatExceptionOfType(UserNotFoundException.class).isThrownBy(login) + assertThatExceptionOfType(UserNotFoundException.class) + .isThrownBy(login) .withMessage(UserNotFoundException.DEFAULT_MESSAGE); } @@ -128,15 +165,19 @@ void failIncorrectPassword() { ThrowingCallable login = () -> userService.login(loginDto); // then - assertThatExceptionOfType(IncorrectPasswordException.class).isThrownBy(login) + assertThatExceptionOfType(IncorrectPasswordException.class) + .isThrownBy(login) .withMessage(IncorrectPasswordException.DEFAULT_MESSAGE); } } private SignupDto generateSignupDto() { + return generateSignupDto(faker.internet().password(8, 30, true, true, true)); + } + + private SignupDto generateSignupDto(String password) { String email = faker.internet().emailAddress(); - String password = faker.internet().password(8, 30, true, true, true); String nickname = faker.internet().username(); return new SignupDto(email, password, nickname); From 4b3322e16a316f1e90f3de669d98e01dde18a7f6 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 08:34:52 +0900 Subject: [PATCH 14/26] style: reformat file --- src/main/java/com/backendoori/ootw/user/domain/User.java | 2 +- .../java/com/backendoori/ootw/user/service/UserService.java | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/user/domain/User.java b/src/main/java/com/backendoori/ootw/user/domain/User.java index a50d51ed..35f4a99a 100644 --- a/src/main/java/com/backendoori/ootw/user/domain/User.java +++ b/src/main/java/com/backendoori/ootw/user/domain/User.java @@ -41,7 +41,7 @@ public class User extends BaseEntity { public User(Long id, String email, String password, String nickname, String image) { AssertUtil.hasPattern(email, RFC5322.REGEX, Message.INVALID_EMAIL); - AssertUtil.notBlank(password,Message.BLANK_PASSWORD); + AssertUtil.notBlank(password, Message.BLANK_PASSWORD); AssertUtil.notBlank(nickname, Message.BLANK_NICKNAME); this.id = id; diff --git a/src/main/java/com/backendoori/ootw/user/service/UserService.java b/src/main/java/com/backendoori/ootw/user/service/UserService.java index 967aa091..082615bc 100644 --- a/src/main/java/com/backendoori/ootw/user/service/UserService.java +++ b/src/main/java/com/backendoori/ootw/user/service/UserService.java @@ -1,9 +1,6 @@ package com.backendoori.ootw.user.service; -import java.util.Objects; import com.backendoori.ootw.common.AssertUtil; -import com.backendoori.ootw.user.exception.AlreadyExistEmailException; -import com.backendoori.ootw.user.exception.IncorrectPasswordException; import com.backendoori.ootw.exception.UserNotFoundException; import com.backendoori.ootw.security.jwt.TokenProvider; import com.backendoori.ootw.user.domain.User; @@ -11,6 +8,8 @@ import com.backendoori.ootw.user.dto.SignupDto; import com.backendoori.ootw.user.dto.TokenDto; import com.backendoori.ootw.user.dto.UserDto; +import com.backendoori.ootw.user.exception.AlreadyExistEmailException; +import com.backendoori.ootw.user.exception.IncorrectPasswordException; import com.backendoori.ootw.user.repository.UserRepository; import com.backendoori.ootw.user.validation.Message; import com.backendoori.ootw.user.validation.Password; From 053ab2dc9e9ed30ce7297774060e46764985cf18 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 08:38:55 +0900 Subject: [PATCH 15/26] =?UTF-8?q?feat:=20400=20status=20handler=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/exception/GlobalControllerAdvice.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java index aa52b3c9..04509400 100644 --- a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java +++ b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java @@ -13,6 +13,14 @@ @RestControllerAdvice public class GlobalControllerAdvice { + @ExceptionHandler(IllegalArgumentException.class) + public ResponseEntity handleIllegalArgumentException(IllegalArgumentException e) { + ErrorResponse errorResponse = new ErrorResponse(e.getMessage()); + + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(errorResponse); + } + @ExceptionHandler(AuthenticationException.class) public ResponseEntity handleAuthenticationException(AuthenticationException e) { ErrorResponse errorResponse = new ErrorResponse(e.getMessage()); From 0c38ff0162f0a10f1b908418f7146d5b231fa575 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 09:16:15 +0900 Subject: [PATCH 16/26] =?UTF-8?q?test:=20=ED=95=84=EC=9A=94=20=EC=97=86?= =?UTF-8?q?=EB=8A=94=20wrapping=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backendoori/ootw/user/domain/UserTest.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/test/java/com/backendoori/ootw/user/domain/UserTest.java b/src/test/java/com/backendoori/ootw/user/domain/UserTest.java index 1444316e..3f1d58d4 100644 --- a/src/test/java/com/backendoori/ootw/user/domain/UserTest.java +++ b/src/test/java/com/backendoori/ootw/user/domain/UserTest.java @@ -11,7 +11,6 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.NullAndEmptySource; @@ -95,14 +94,14 @@ void testCreateBlankNickName(String nickname) { .withMessage(Message.BLANK_NICKNAME); } - private static Stream generateInvalidEmails() { + private static Stream generateInvalidEmails() { return Stream.of( - Arguments.of(faker.app().name()), - Arguments.of(faker.name().fullName()), - Arguments.of(faker.internet().url()), - Arguments.of(faker.internet().domainName()), - Arguments.of(faker.internet().webdomain()), - Arguments.of(faker.internet().botUserAgentAny()) + faker.app().name(), + faker.name().fullName(), + faker.internet().url(), + faker.internet().domainName(), + faker.internet().webdomain(), + faker.internet().botUserAgentAny() ); } From 315f3a1225d8130d6424bdba2930cbb64c7e45c6 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 09:16:42 +0900 Subject: [PATCH 17/26] =?UTF-8?q?feat:=20user=20controller=20validation=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/backendoori/ootw/user/controller/UserController.java | 3 ++- src/main/java/com/backendoori/ootw/user/dto/SignupDto.java | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/backendoori/ootw/user/controller/UserController.java b/src/main/java/com/backendoori/ootw/user/controller/UserController.java index fc97f46d..30a62917 100644 --- a/src/main/java/com/backendoori/ootw/user/controller/UserController.java +++ b/src/main/java/com/backendoori/ootw/user/controller/UserController.java @@ -6,6 +6,7 @@ import com.backendoori.ootw.user.dto.TokenDto; import com.backendoori.ootw.user.dto.UserDto; import com.backendoori.ootw.user.service.UserService; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -23,7 +24,7 @@ public class UserController { private final UserService userService; @PostMapping("/signup") - public ResponseEntity signup(@RequestBody SignupDto signupDto) { + public ResponseEntity signup(@RequestBody @Valid SignupDto signupDto) { UserDto userDto = userService.signup(signupDto); return ResponseEntity.status(HttpStatus.CREATED) diff --git a/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java b/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java index f53c5008..59b368c3 100644 --- a/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java +++ b/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java @@ -9,6 +9,7 @@ public record SignupDto( @NotNull + @NotBlank @Email(regexp = RFC5322.REGEX) String email, From 55210c0f029406af16ca463374b5a421369efe03 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 09:17:27 +0900 Subject: [PATCH 18/26] =?UTF-8?q?feat:=20jakarta=20annotation=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20handler=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/GlobalControllerAdvice.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java index 04509400..721a4671 100644 --- a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java +++ b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java @@ -1,11 +1,16 @@ package com.backendoori.ootw.exception; +import java.util.List; import java.util.NoSuchElementException; +import java.util.Objects; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.dao.DuplicateKeyException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.AuthenticationException; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -21,6 +26,21 @@ public ResponseEntity handleIllegalArgumentException(IllegalArgum .body(errorResponse); } + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { + List errors = e.getFieldErrors(); + String message = errors.stream() + .map(DefaultMessageSourceResolvable::getDefaultMessage) + .filter(Objects::nonNull) + .findFirst() + .orElseThrow(); + + ErrorResponse errorResponse = new ErrorResponse(message); + + return ResponseEntity.badRequest() + .body(errorResponse); + } + @ExceptionHandler(AuthenticationException.class) public ResponseEntity handleAuthenticationException(AuthenticationException e) { ErrorResponse errorResponse = new ErrorResponse(e.getMessage()); @@ -55,4 +75,5 @@ public ResponseEntity handleException(Exception e) { .body(errorResponse); } + } From 222898d24e0a2344168709c127ad78cd89760161 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 09:18:00 +0900 Subject: [PATCH 19/26] =?UTF-8?q?test:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EC=8B=9C=20=EC=9E=98=EB=AA=BB=EB=90=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=A9=94=EC=9D=BC=EC=97=90=20=EB=8C=80=ED=95=9C=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserControllerTest.java | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java index 012612d2..a632612c 100644 --- a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java +++ b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java @@ -10,20 +10,24 @@ import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; -import com.backendoori.ootw.user.exception.AlreadyExistEmailException; -import com.backendoori.ootw.user.exception.IncorrectPasswordException; +import java.util.stream.Stream; import com.backendoori.ootw.exception.UserNotFoundException; import com.backendoori.ootw.security.jwt.TokenProvider; import com.backendoori.ootw.user.dto.LoginDto; import com.backendoori.ootw.user.dto.SignupDto; import com.backendoori.ootw.user.dto.TokenDto; import com.backendoori.ootw.user.dto.UserDto; +import com.backendoori.ootw.user.exception.AlreadyExistEmailException; +import com.backendoori.ootw.user.exception.IncorrectPasswordException; import com.backendoori.ootw.user.service.UserService; import com.fasterxml.jackson.databind.ObjectMapper; import net.datafaker.Faker; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.NullAndEmptySource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -78,6 +82,27 @@ void created() throws Exception { .andExpect(jsonPath("$.updatedAt", startsWith(removeMills(userDto.updatedAt())))); } + @DisplayName("잘못된 형식의 email일 경우 400 status를 반환한다") + @NullAndEmptySource + @MethodSource("generateInvalidEmails") + @ParameterizedTest + void badRequestInvalidEmail(String email) throws Exception { + // given + String password = faker.internet().password(8, 30, true, true, true); + String nickname = faker.internet().username(); + SignupDto signupDto = new SignupDto(email, password, nickname); + + // when + ResultActions actions = mockMvc.perform( + post("/api/v1/auth/signup") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(signupDto))); + + // then + actions.andExpect(status().isBadRequest()); + } + @DisplayName("이미 등록된 email일 경우 409 status를 반환한다") @Test void unauthorizedAlreadyExistEmail() throws Exception { @@ -97,6 +122,17 @@ void unauthorizedAlreadyExistEmail() throws Exception { actions.andExpect(status().isConflict()); } + private static Stream generateInvalidEmails() { + return Stream.of( + faker.app().name(), + faker.name().fullName(), + faker.internet().url(), + faker.internet().domainName(), + faker.internet().webdomain(), + faker.internet().botUserAgentAny() + ); + } + } @DisplayName("로그인 테스트") @@ -166,9 +202,8 @@ void unauthorizedIncorrectPassword() throws Exception { private SignupDto generateSignupDto() { String email = faker.internet().emailAddress(); - String password = faker.internet().password(); + String password = faker.internet().password(8, 30, true, true, true); String nickname = faker.internet().username(); - String image = faker.internet().url(); return new SignupDto(email, password, nickname); } From ea4877642dc9cdf995a31816de7dea642ac9a516 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 09:21:04 +0900 Subject: [PATCH 20/26] =?UTF-8?q?test:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EC=8B=9C=20=EC=9E=98=EB=AA=BB=EB=90=9C=20=ED=98=95?= =?UTF-8?q?=EC=8B=9D=EC=9D=98=20=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserControllerTest.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java index a632612c..e83cfaaa 100644 --- a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java +++ b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java @@ -103,6 +103,27 @@ void badRequestInvalidEmail(String email) throws Exception { actions.andExpect(status().isBadRequest()); } + @DisplayName("잘못된 형식의 비밀번호의 경우 400 status를 반환한다") + @NullAndEmptySource + @MethodSource("generateInvalidPasswords") + @ParameterizedTest + void badRequestInvalidPassword(String password) throws Exception { + // given + String email = faker.internet().emailAddress(); + String nickname = faker.internet().username(); + SignupDto signupDto = new SignupDto(email, password, nickname); + + // when + ResultActions actions = mockMvc.perform( + post("/api/v1/auth/signup") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(signupDto))); + + // then + actions.andExpect(status().isBadRequest()); + } + @DisplayName("이미 등록된 email일 경우 409 status를 반환한다") @Test void unauthorizedAlreadyExistEmail() throws Exception { @@ -133,6 +154,15 @@ private static Stream generateInvalidEmails() { ); } + private static Stream generateInvalidPasswords() { + return Stream.of( + faker.internet().password(1, 7, true, true, true), + faker.internet().password(31, 50, true, true, true), + faker.internet().password(8, 30, true, false, true), + faker.internet().password(8, 30, true, true, false) + ); + } + } @DisplayName("로그인 테스트") From 091e43a9caeeec7cf9e8e64304e099fa1e8c30d6 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 09:23:39 +0900 Subject: [PATCH 21/26] =?UTF-8?q?test:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EC=8B=9C=20=EA=B3=B5=EB=B0=B1=20=EB=8B=89=EB=84=A4?= =?UTF-8?q?=EC=9E=84=EC=97=90=20=EB=8C=80=ED=95=9C=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserControllerTest.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java index e83cfaaa..d140292b 100644 --- a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java +++ b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java @@ -124,6 +124,26 @@ void badRequestInvalidPassword(String password) throws Exception { actions.andExpect(status().isBadRequest()); } + @DisplayName("닉네임이 공백일 경우 400 status를 반환한다") + @NullAndEmptySource + @ParameterizedTest + void badRequestBlankNickname(String nickname) throws Exception { + // given + String email = faker.internet().emailAddress(); + String password = faker.internet().password(8, 30, true, true, true); + SignupDto signupDto = new SignupDto(email, password, nickname); + + // when + ResultActions actions = mockMvc.perform( + post("/api/v1/auth/signup") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(signupDto))); + + // then + actions.andExpect(status().isBadRequest()); + } + @DisplayName("이미 등록된 email일 경우 409 status를 반환한다") @Test void unauthorizedAlreadyExistEmail() throws Exception { From 4da69ac63c862c88eb1aa12cef31f87802eeea72 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 09:25:37 +0900 Subject: [PATCH 22/26] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EA=B0=92=EC=97=90=20=EB=8C=80=ED=95=9C=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/user/controller/UserController.java | 2 +- .../java/com/backendoori/ootw/user/dto/LoginDto.java | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/backendoori/ootw/user/controller/UserController.java b/src/main/java/com/backendoori/ootw/user/controller/UserController.java index 30a62917..bf9eb119 100644 --- a/src/main/java/com/backendoori/ootw/user/controller/UserController.java +++ b/src/main/java/com/backendoori/ootw/user/controller/UserController.java @@ -32,7 +32,7 @@ public ResponseEntity signup(@RequestBody @Valid SignupDto signupDto) { } @PostMapping("/login") - public ResponseEntity login(@RequestBody LoginDto loginDto) { + public ResponseEntity login(@RequestBody @Valid LoginDto loginDto) { TokenDto tokenDto = userService.login(loginDto); HttpHeaders httpHeaders = new HttpHeaders(); diff --git a/src/main/java/com/backendoori/ootw/user/dto/LoginDto.java b/src/main/java/com/backendoori/ootw/user/dto/LoginDto.java index 1add5ec0..a2667b18 100644 --- a/src/main/java/com/backendoori/ootw/user/dto/LoginDto.java +++ b/src/main/java/com/backendoori/ootw/user/dto/LoginDto.java @@ -1,7 +1,19 @@ package com.backendoori.ootw.user.dto; +import com.backendoori.ootw.user.validation.Password; +import com.backendoori.ootw.user.validation.RFC5322; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + public record LoginDto( + @NotNull + @NotBlank + @Email(regexp = RFC5322.REGEX) String email, + + @NotNull + @Password String password ) { From f927ce4b6ed8708c76ca7bbdbe0752fbb8a5e2cf Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 09:33:05 +0900 Subject: [PATCH 23/26] =?UTF-8?q?feat:=20global=20controller=20advice=20?= =?UTF-8?q?=EA=B8=B0=EB=B3=B8=20=EB=A9=94=EC=8B=9C=EC=A7=80=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 --- .../backendoori/ootw/exception/GlobalControllerAdvice.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java index 721a4671..2a375a51 100644 --- a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java +++ b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java @@ -18,6 +18,8 @@ @RestControllerAdvice public class GlobalControllerAdvice { + public static final String DEFAULT_MESSAGE = "유효하지 않은 요청 입니다."; + @ExceptionHandler(IllegalArgumentException.class) public ResponseEntity handleIllegalArgumentException(IllegalArgumentException e) { ErrorResponse errorResponse = new ErrorResponse(e.getMessage()); @@ -33,7 +35,7 @@ public ResponseEntity handleMethodArgumentNotValidException(Metho .map(DefaultMessageSourceResolvable::getDefaultMessage) .filter(Objects::nonNull) .findFirst() - .orElseThrow(); + .orElse(DEFAULT_MESSAGE); ErrorResponse errorResponse = new ErrorResponse(message); From 475eaa7ea1f102e1f88e630eb66ed8a13cb4b1a7 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 10:24:39 +0900 Subject: [PATCH 24/26] =?UTF-8?q?test:=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backendoori/ootw/user/controller/UserControllerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java index d140292b..d56b7fd4 100644 --- a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java +++ b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java @@ -272,7 +272,7 @@ private UserDto createUser(SignupDto signupDto) { private LoginDto generateLoginDto() { String email = faker.internet().emailAddress(); - String password = faker.internet().password(); + String password = faker.internet().password(8, 30, true, true, true); return new LoginDto(email, password); } From edf3674718c29f7b355918b0e023404fb4ca0d1e Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 10:40:25 +0900 Subject: [PATCH 25/26] =?UTF-8?q?test:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=EC=97=90=20=EB=8C=80=ED=95=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=A9=94=EC=9D=BC,=20=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EA=B2=80=EC=A6=9D=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserControllerTest.java | 99 ++++++++++++++----- 1 file changed, 76 insertions(+), 23 deletions(-) diff --git a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java index d56b7fd4..3280063e 100644 --- a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java +++ b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java @@ -25,8 +25,11 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; import org.junit.jupiter.params.provider.NullAndEmptySource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; @@ -84,7 +87,7 @@ void created() throws Exception { @DisplayName("잘못된 형식의 email일 경우 400 status를 반환한다") @NullAndEmptySource - @MethodSource("generateInvalidEmails") + @ArgumentsSource(InvalidEmailProvider.class) @ParameterizedTest void badRequestInvalidEmail(String email) throws Exception { // given @@ -105,7 +108,7 @@ void badRequestInvalidEmail(String email) throws Exception { @DisplayName("잘못된 형식의 비밀번호의 경우 400 status를 반환한다") @NullAndEmptySource - @MethodSource("generateInvalidPasswords") + @ArgumentsSource(InvalidPasswordProvider.class) @ParameterizedTest void badRequestInvalidPassword(String password) throws Exception { // given @@ -163,26 +166,6 @@ void unauthorizedAlreadyExistEmail() throws Exception { actions.andExpect(status().isConflict()); } - private static Stream generateInvalidEmails() { - return Stream.of( - faker.app().name(), - faker.name().fullName(), - faker.internet().url(), - faker.internet().domainName(), - faker.internet().webdomain(), - faker.internet().botUserAgentAny() - ); - } - - private static Stream generateInvalidPasswords() { - return Stream.of( - faker.internet().password(1, 7, true, true, true), - faker.internet().password(31, 50, true, true, true), - faker.internet().password(8, 30, true, false, true), - faker.internet().password(8, 30, true, true, false) - ); - } - } @DisplayName("로그인 테스트") @@ -210,6 +193,26 @@ void created() throws Exception { .andExpect(jsonPath("$.token", is(tokenDto.token()))); } + @DisplayName("잘못된 형식의 email일 경우 400 status를 반환한다") + @NullAndEmptySource + @ArgumentsSource(InvalidEmailProvider.class) + @ParameterizedTest + void badRequestInvalidEmail(String email) throws Exception { + // given + String password = faker.internet().password(8, 30, true, true, true); + LoginDto loginDto = new LoginDto(email, password); + + // when + ResultActions actions = mockMvc.perform( + post("/api/v1/auth/login") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(loginDto))); + + // then + actions.andExpect(status().isBadRequest()); + } + @DisplayName("email이 일치하는 사용자가 없으면 404 status를 반환한다") @Test void unauthorizedNotExistUser() throws Exception { @@ -229,6 +232,26 @@ void unauthorizedNotExistUser() throws Exception { actions.andExpect(status().isNotFound()); } + @DisplayName("잘못된 형식의 비밀번호의 경우 400 status를 반환한다") + @NullAndEmptySource + @ArgumentsSource(InvalidPasswordProvider.class) + @ParameterizedTest + void badRequestInvalidPassword(String password) throws Exception { + // given + String email = faker.internet().emailAddress(); + LoginDto loginDto = new LoginDto(email, password); + + // when + ResultActions actions = mockMvc.perform( + post("/api/v1/auth/login") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(loginDto))); + + // then + actions.andExpect(status().isBadRequest()); + } + @DisplayName("비밀번호가 일치하지 않으면 401 status를 반환한다") @Test void unauthorizedIncorrectPassword() throws Exception { @@ -281,4 +304,34 @@ private String removeMills(LocalDateTime localDateTime) { return localDateTime.truncatedTo(ChronoUnit.SECONDS).toString(); } + static class InvalidEmailProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext extensionContext) { + return Stream.of( + Arguments.of(faker.app().name()), + Arguments.of(faker.name().fullName()), + Arguments.of(faker.internet().url()), + Arguments.of(faker.internet().domainName()), + Arguments.of(faker.internet().webdomain()), + Arguments.of(faker.internet().botUserAgentAny()) + ); + } + + } + + static class InvalidPasswordProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext extensionContext) { + return Stream.of( + Arguments.of(faker.internet().password(1, 7, true, true, true)), + Arguments.of(faker.internet().password(31, 50, true, true, true)), + Arguments.of(faker.internet().password(8, 30, true, false, true)), + Arguments.of(faker.internet().password(8, 30, true, true, false)) + ); + } + + } + } From 5bb4948a212284a079661129b4b2040290ba605a Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 15:03:39 +0900 Subject: [PATCH 26/26] =?UTF-8?q?refactor:=20error=20response=20=ED=86=B5?= =?UTF-8?q?=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/exception/ExceptionResponse.java | 38 ----------------- .../exception/GlobalControllerAdvice.java | 42 ++++++++----------- .../post/controller/PostControllerTest.java | 16 +++---- 3 files changed, 23 insertions(+), 73 deletions(-) delete mode 100644 src/main/java/com/backendoori/ootw/exception/ExceptionResponse.java diff --git a/src/main/java/com/backendoori/ootw/exception/ExceptionResponse.java b/src/main/java/com/backendoori/ootw/exception/ExceptionResponse.java deleted file mode 100644 index 242cfd29..00000000 --- a/src/main/java/com/backendoori/ootw/exception/ExceptionResponse.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.backendoori.ootw.exception; - -import java.util.List; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.MethodArgumentNotValidException; - -public record ExceptionResponse( - T error -) { - - public static ExceptionResponse> from( - MethodArgumentNotValidException e) { - List errors = e.getBindingResult() - .getFieldErrors() - .stream() - .map(fieldError -> - new FieldErrorDetail(fieldError.getField(), fieldError.getDefaultMessage())) - .toList(); - - return new ExceptionResponse<>(errors); - } - - public static ExceptionResponse from(E e) { - return new ExceptionResponse<>(e.getMessage()); - } - - @RequiredArgsConstructor(access = AccessLevel.PROTECTED) - @Getter - public static class FieldErrorDetail { - - private final String field; - private final String defaultMessage; - - } - -} diff --git a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java index 94d11067..cf184ae0 100644 --- a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java +++ b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java @@ -3,7 +3,6 @@ import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; -import com.backendoori.ootw.exception.ExceptionResponse.FieldErrorDetail; import lombok.extern.slf4j.Slf4j; import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.dao.DuplicateKeyException; @@ -41,7 +40,20 @@ public ResponseEntity handleMethodArgumentNotValidException(Metho ErrorResponse errorResponse = new ErrorResponse(message); - return ResponseEntity.badRequest() + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(errorResponse); + } + + @ExceptionHandler(HandlerMethodValidationException.class) + public ResponseEntity handlerMethodValidationException(HandlerMethodValidationException e) { + String errorMessage = e.getAllValidationResults() + .get(0) + .getResolvableErrors() + .get(0) + .getDefaultMessage(); + ErrorResponse errorResponse = new ErrorResponse(errorMessage); + + return ResponseEntity.status(HttpStatus.BAD_REQUEST) .body(errorResponse); } @@ -69,29 +81,12 @@ public ResponseEntity handleDuplicateKeyException(DuplicateKeyExc .body(errorResponse); } - @ExceptionHandler(HandlerMethodValidationException.class) - public ResponseEntity handlerMethodValidationException(HandlerMethodValidationException e) { - String errorMessage = e.getAllValidationResults() - .get(0) - .getResolvableErrors() - .get(0) - .getDefaultMessage(); - ErrorResponse errorResponse = new ErrorResponse(errorMessage); - - return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .body(errorResponse); - } - - @ExceptionHandler(IllegalArgumentException.class) - public ResponseEntity> handleIllegalArgumentException(IllegalArgumentException e) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .body(ExceptionResponse.from(e)); - } - @ExceptionHandler(ImageUploadException.class) - public ResponseEntity> handleImageUploadException(ImageUploadException e) { + public ResponseEntity handleImageUploadException(ImageUploadException e) { + ErrorResponse errorResponse = new ErrorResponse(e.getMessage()); + return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY) - .body(ExceptionResponse.from(e)); + .body(errorResponse); } @ExceptionHandler(Exception.class) @@ -104,5 +99,4 @@ public ResponseEntity handleException(Exception e) { .body(errorResponse); } - } diff --git a/src/test/java/com/backendoori/ootw/post/controller/PostControllerTest.java b/src/test/java/com/backendoori/ootw/post/controller/PostControllerTest.java index 1f216ea8..8403ad94 100644 --- a/src/test/java/com/backendoori/ootw/post/controller/PostControllerTest.java +++ b/src/test/java/com/backendoori/ootw/post/controller/PostControllerTest.java @@ -3,15 +3,15 @@ import static com.backendoori.ootw.security.jwt.JwtAuthenticationFilter.TOKEN_HEADER; import static com.backendoori.ootw.security.jwt.JwtAuthenticationFilter.TOKEN_PREFIX; import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.instanceOf; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.nio.charset.StandardCharsets; import java.util.List; -import com.backendoori.ootw.exception.ExceptionResponse; -import com.backendoori.ootw.exception.ExceptionResponse.FieldErrorDetail; import com.backendoori.ootw.post.dto.PostReadResponse; import com.backendoori.ootw.post.dto.PostSaveRequest; import com.backendoori.ootw.post.dto.PostSaveResponse; @@ -173,16 +173,10 @@ void saveFailByMethodArgumentNotValidException() throws Exception { .accept(MediaType.APPLICATION_JSON); // then - String response = mockMvc.perform(requestBuilder) + mockMvc.perform(requestBuilder) .andExpect(status().isBadRequest()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andReturn() - .getResponse() - .getContentAsString(StandardCharsets.UTF_8); - - ExceptionResponse> exceptionResponse = - objectMapper.readValue(response, ExceptionResponse.class); - assertThat(exceptionResponse.error()).hasSize(1); + .andExpect(jsonPath("$.message", instanceOf(String.class))) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)); } @Test