From 9e8131c47f1db2f429fa473802b3d008e04fc7cd Mon Sep 17 00:00:00 2001 From: juhyeon Date: Mon, 7 Aug 2023 08:11:50 +0900 Subject: [PATCH 01/36] =?UTF-8?q?test=20:=20JwtUtil.encode=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assignment/utils/JwtUtilTest.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java diff --git a/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java b/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java new file mode 100644 index 000000000..e215575d7 --- /dev/null +++ b/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java @@ -0,0 +1,26 @@ +package com.codesoom.assignment.utils; + + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.*; + +@SuppressWarnings({"InnerClassMayBeStatic", "NonAsciiCharacters"}) +@DisplayName("JwtUtil 클래스") +class JwtUtilTest { + private final String SECRET = "12345678901234567890123456789010"; + private final String VALID_TOKEN = ""; + JwtUtil jwtUtil = new JwtUtil(SECRET); + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class Describe_encode { + @DisplayName("유저 아이디를 받아 토큰을 생성한다.") + @Test + void It_returns_token() { + String token = jwtUtil.encode(1L); + + Assertions.assertThat(token).isNotNull(); + Assertions.assertThat(token).isEqualTo(VALID_TOKEN); + } + } +} From 7668f36011b6e1976251579df415ccd2b66d3e13 Mon Sep 17 00:00:00 2001 From: juhyeon Date: Mon, 7 Aug 2023 08:17:13 +0900 Subject: [PATCH 02/36] =?UTF-8?q?feat=20:=20JwtUtil.encode=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../codesoom/assignment/utils/JwtUtil.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 app/src/main/java/com/codesoom/assignment/utils/JwtUtil.java diff --git a/app/src/main/java/com/codesoom/assignment/utils/JwtUtil.java b/app/src/main/java/com/codesoom/assignment/utils/JwtUtil.java new file mode 100644 index 000000000..0101504f5 --- /dev/null +++ b/app/src/main/java/com/codesoom/assignment/utils/JwtUtil.java @@ -0,0 +1,27 @@ +package com.codesoom.assignment.utils; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; +import org.springframework.beans.factory.annotation.Value; + +import java.security.Key; + +public class JwtUtil { + private final Key key; + + public JwtUtil(@Value("${jwt.secret}") String secret) { + this.key = Keys.hmacShaKeyFor(secret.getBytes()); + } + + public String encode(Long userId) { + return Jwts.builder() + .claim("userId", userId) + .signWith(key) + .compact(); + } + + public Claims decode(String token) { + return null; + } +} From ed21b82a4a7324589006d26f5cedbd06cc0339fb Mon Sep 17 00:00:00 2001 From: juhyeon Date: Mon, 7 Aug 2023 08:17:52 +0900 Subject: [PATCH 03/36] =?UTF-8?q?test=20:=20JwtUtil.encode=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - VALID_TOKEN 추가 --- .../java/com/codesoom/assignment/utils/JwtUtilTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java b/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java index e215575d7..39616a72e 100644 --- a/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java +++ b/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java @@ -8,16 +8,16 @@ @DisplayName("JwtUtil 클래스") class JwtUtilTest { private final String SECRET = "12345678901234567890123456789010"; - private final String VALID_TOKEN = ""; + private final String VALID_TOKEN = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.neCsyNLzy3lQ4o2yliotWT06FwSGZagaHpKdAkjnGGw"; JwtUtil jwtUtil = new JwtUtil(SECRET); - + private final Long USER_ID = 1L; @Nested @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) - class Describe_encode { + class encode_메서드는 { @DisplayName("유저 아이디를 받아 토큰을 생성한다.") @Test void It_returns_token() { - String token = jwtUtil.encode(1L); + String token = jwtUtil.encode(USER_ID); Assertions.assertThat(token).isNotNull(); Assertions.assertThat(token).isEqualTo(VALID_TOKEN); From bba4225e3ac2908d7f7ccecb646667f0db05e0a6 Mon Sep 17 00:00:00 2001 From: juhyeon Date: Mon, 7 Aug 2023 08:21:43 +0900 Subject: [PATCH 04/36] =?UTF-8?q?test=20:=20JwtUtil.decode=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../codesoom/assignment/utils/JwtUtilTest.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java b/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java index 39616a72e..ff7776e31 100644 --- a/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java +++ b/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java @@ -4,6 +4,8 @@ import org.assertj.core.api.Assertions; import org.junit.jupiter.api.*; +import static org.assertj.core.api.Assertions.*; + @SuppressWarnings({"InnerClassMayBeStatic", "NonAsciiCharacters"}) @DisplayName("JwtUtil 클래스") class JwtUtilTest { @@ -11,6 +13,7 @@ class JwtUtilTest { private final String VALID_TOKEN = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.neCsyNLzy3lQ4o2yliotWT06FwSGZagaHpKdAkjnGGw"; JwtUtil jwtUtil = new JwtUtil(SECRET); private final Long USER_ID = 1L; + @Nested @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) class encode_메서드는 { @@ -19,8 +22,19 @@ class encode_메서드는 { void It_returns_token() { String token = jwtUtil.encode(USER_ID); - Assertions.assertThat(token).isNotNull(); - Assertions.assertThat(token).isEqualTo(VALID_TOKEN); + assertThat(token).isNotNull(); + assertThat(token).isEqualTo(VALID_TOKEN); + } + } + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class decode_메서드는 { + @DisplayName("토큰을 파싱하여 클레임을 반환한다.") + @Test + void It_returns_claims() { + assertThat(jwtUtil.decode(VALID_TOKEN)).isNotNull(); + assertThat(jwtUtil.decode(VALID_TOKEN).get("userId")).isEqualTo(USER_ID); } } } From fa88c9cd39967dfba6a16db4471537d41d32d348 Mon Sep 17 00:00:00 2001 From: juhyeon Date: Mon, 7 Aug 2023 08:25:21 +0900 Subject: [PATCH 05/36] =?UTF-8?q?feat=20:=20JwtUtil.decode=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/codesoom/assignment/utils/JwtUtil.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/codesoom/assignment/utils/JwtUtil.java b/app/src/main/java/com/codesoom/assignment/utils/JwtUtil.java index 0101504f5..8198032fe 100644 --- a/app/src/main/java/com/codesoom/assignment/utils/JwtUtil.java +++ b/app/src/main/java/com/codesoom/assignment/utils/JwtUtil.java @@ -22,6 +22,10 @@ public String encode(Long userId) { } public Claims decode(String token) { - return null; + return Jwts.parserBuilder() + .setSigningKey(key) + .build() + .parseClaimsJws(token) + .getBody(); } } From 8993888631e3536b525f6e13b73d50d78b7fc6ec Mon Sep 17 00:00:00 2001 From: juhyeon Date: Mon, 7 Aug 2023 08:29:50 +0900 Subject: [PATCH 06/36] =?UTF-8?q?test=20:=20JwtUtil.decode=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 파싱 결과 형 변환 추가 --- .../test/java/com/codesoom/assignment/utils/JwtUtilTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java b/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java index ff7776e31..89c98a97d 100644 --- a/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java +++ b/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java @@ -34,7 +34,7 @@ class decode_메서드는 { @Test void It_returns_claims() { assertThat(jwtUtil.decode(VALID_TOKEN)).isNotNull(); - assertThat(jwtUtil.decode(VALID_TOKEN).get("userId")).isEqualTo(USER_ID); + assertThat(jwtUtil.decode(VALID_TOKEN).get("userId",Long.class)).isEqualTo(USER_ID); } } } From 77923989431a69a5806a5f182a68f2f8e11345f4 Mon Sep 17 00:00:00 2001 From: juhyeon Date: Tue, 8 Aug 2023 07:56:27 +0900 Subject: [PATCH 07/36] =?UTF-8?q?test=20:=20AuthenticationService=20login?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/AuthenticationService.java | 12 +++++ .../assignment/domain/UserRepository.java | 2 + .../assignment/dto/UserLoginData.java | 26 +++++++++++ .../assignment/infra/JpaUserRepository.java | 2 + .../codesoom/assignment/utils/JwtUtil.java | 2 + .../AuthenticationServiceTest.java | 46 +++++++++++++++++++ .../assignment/application/JpaTest.java | 22 +++++++++ 7 files changed, 112 insertions(+) create mode 100644 app/src/main/java/com/codesoom/assignment/application/AuthenticationService.java create mode 100644 app/src/main/java/com/codesoom/assignment/dto/UserLoginData.java create mode 100644 app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java create mode 100644 app/src/test/java/com/codesoom/assignment/application/JpaTest.java diff --git a/app/src/main/java/com/codesoom/assignment/application/AuthenticationService.java b/app/src/main/java/com/codesoom/assignment/application/AuthenticationService.java new file mode 100644 index 000000000..5c731966d --- /dev/null +++ b/app/src/main/java/com/codesoom/assignment/application/AuthenticationService.java @@ -0,0 +1,12 @@ +package com.codesoom.assignment.application; + +import com.codesoom.assignment.domain.UserRepository; +import com.codesoom.assignment.utils.JwtUtil; +import org.springframework.stereotype.Service; + +@Service +public class AuthenticationService { + + public AuthenticationService(UserRepository userRepository, JwtUtil jwtUtil) { + } +} diff --git a/app/src/main/java/com/codesoom/assignment/domain/UserRepository.java b/app/src/main/java/com/codesoom/assignment/domain/UserRepository.java index 995d6395a..5019fae54 100644 --- a/app/src/main/java/com/codesoom/assignment/domain/UserRepository.java +++ b/app/src/main/java/com/codesoom/assignment/domain/UserRepository.java @@ -12,4 +12,6 @@ public interface UserRepository { Optional findByIdAndDeletedIsFalse(Long id); Optional findByEmail(String email); + + void deleteAll(); } diff --git a/app/src/main/java/com/codesoom/assignment/dto/UserLoginData.java b/app/src/main/java/com/codesoom/assignment/dto/UserLoginData.java new file mode 100644 index 000000000..695e8f04c --- /dev/null +++ b/app/src/main/java/com/codesoom/assignment/dto/UserLoginData.java @@ -0,0 +1,26 @@ +package com.codesoom.assignment.dto; + +import com.github.dozermapper.core.Mapping; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UserLoginData { + @NotBlank + @Size(min = 3) + @Mapping("email") + private String email; + + @NotBlank + @Size(min = 4, max = 1024) + @Mapping("password") + private String password; +} diff --git a/app/src/main/java/com/codesoom/assignment/infra/JpaUserRepository.java b/app/src/main/java/com/codesoom/assignment/infra/JpaUserRepository.java index 7e8205836..4e3995820 100644 --- a/app/src/main/java/com/codesoom/assignment/infra/JpaUserRepository.java +++ b/app/src/main/java/com/codesoom/assignment/infra/JpaUserRepository.java @@ -17,4 +17,6 @@ public interface JpaUserRepository Optional findByIdAndDeletedIsFalse(Long id); Optional findByEmail(String email); + + void deleteAll(); } diff --git a/app/src/main/java/com/codesoom/assignment/utils/JwtUtil.java b/app/src/main/java/com/codesoom/assignment/utils/JwtUtil.java index 8198032fe..f7719be11 100644 --- a/app/src/main/java/com/codesoom/assignment/utils/JwtUtil.java +++ b/app/src/main/java/com/codesoom/assignment/utils/JwtUtil.java @@ -4,9 +4,11 @@ import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; import java.security.Key; +@Component public class JwtUtil { private final Key key; diff --git a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java new file mode 100644 index 000000000..3963fc4d4 --- /dev/null +++ b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java @@ -0,0 +1,46 @@ +package com.codesoom.assignment.application; + +import com.codesoom.assignment.domain.User; +import com.codesoom.assignment.dto.UserLoginData; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.*; + + +@SuppressWarnings({"InnerClassMayBeStatic", "NonAsciiCharacters"}) +@DisplayName("AuthenticationService 클래스") +class AuthenticationServiceTest extends JpaTest{ + private AuthenticationService authenticationService = new AuthenticationService(getUserRepository(), getJwtUtil()); + private final String VALID_TOKEN = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.neCsyNLzy3lQ4o2yliotWT06FwSGZagaHpKdAkjnGGw"; + + private final String AUTH_NAME = "AUTH_NAME"; + private final String AUTH_EMAIL = "auth@foo.com"; + private final String AUTH_PASSWORD = "12345678"; + + + + private UserLoginData AUTH_USER_DATA = UserLoginData.builder() + .email(AUTH_EMAIL) + .password(AUTH_PASSWORD) + .build(); + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class login_메서드는 { + @BeforeEach + void setUp() { + getUserRepository().deleteAll(); + getUserRepository().save(User.builder() + .name(AUTH_NAME) + .email(AUTH_EMAIL) + .password(AUTH_PASSWORD) + .build()); + } + + @DisplayName("유저로그인정보를 받아 인증토큰을 반환한다.") + void It_returns_token() { + String accessToken = authenticationService.login(AUTH_USER_DATA); + Assertions.assertThat(accessToken).isNotNull(); + Assertions.assertThat(accessToken).isEqualTo(VALID_TOKEN); + } + } +} diff --git a/app/src/test/java/com/codesoom/assignment/application/JpaTest.java b/app/src/test/java/com/codesoom/assignment/application/JpaTest.java new file mode 100644 index 000000000..529501fbc --- /dev/null +++ b/app/src/test/java/com/codesoom/assignment/application/JpaTest.java @@ -0,0 +1,22 @@ +package com.codesoom.assignment.application; + +import com.codesoom.assignment.domain.UserRepository; +import com.codesoom.assignment.utils.JwtUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +@DataJpaTest +public class JpaTest { + @Autowired + public UserRepository userRepository; + @Autowired + public JwtUtil jwtUtil; + + public UserRepository getUserRepository() { + return userRepository; + } + + public JwtUtil getJwtUtil() { + return jwtUtil; + } +} From 6f34f1424e9b5e4c774c8d0d54f7ca648ff9c205 Mon Sep 17 00:00:00 2001 From: juhyeon Date: Tue, 8 Aug 2023 07:57:05 +0900 Subject: [PATCH 08/36] =?UTF-8?q?chore=20:=20=EB=88=84=EB=9D=BD=EB=90=9C?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=96=B4=EB=85=B8=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assignment/application/AuthenticationServiceTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java index 3963fc4d4..b97875a2f 100644 --- a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java +++ b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java @@ -37,6 +37,7 @@ void setUp() { } @DisplayName("유저로그인정보를 받아 인증토큰을 반환한다.") + @Test void It_returns_token() { String accessToken = authenticationService.login(AUTH_USER_DATA); Assertions.assertThat(accessToken).isNotNull(); From 2e7d5e048f189ddc60cad107c6eb1044324547a1 Mon Sep 17 00:00:00 2001 From: juhyeon Date: Tue, 8 Aug 2023 08:19:00 +0900 Subject: [PATCH 09/36] =?UTF-8?q?feat=20:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/AuthenticationService.java | 16 ++++++++++++++++ .../application/AuthenticationServiceTest.java | 8 +++++--- .../codesoom/assignment/application/JpaTest.java | 4 ++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/codesoom/assignment/application/AuthenticationService.java b/app/src/main/java/com/codesoom/assignment/application/AuthenticationService.java index 5c731966d..aa1bd831e 100644 --- a/app/src/main/java/com/codesoom/assignment/application/AuthenticationService.java +++ b/app/src/main/java/com/codesoom/assignment/application/AuthenticationService.java @@ -1,12 +1,28 @@ package com.codesoom.assignment.application; +import com.codesoom.assignment.domain.User; import com.codesoom.assignment.domain.UserRepository; +import com.codesoom.assignment.dto.UserLoginData; import com.codesoom.assignment.utils.JwtUtil; import org.springframework.stereotype.Service; @Service public class AuthenticationService { + private final UserRepository userRepository; + private final JwtUtil jwtUtil; public AuthenticationService(UserRepository userRepository, JwtUtil jwtUtil) { + this.userRepository = userRepository; + this.jwtUtil = jwtUtil; + } + + public String login(UserLoginData loginData) { + User loginUser = userRepository.findByEmail(loginData.getEmail()) + .orElseThrow(() -> new IllegalArgumentException("Invalid email address")); + + if (!loginUser.getPassword().equals(loginData.getPassword())) { + throw new IllegalArgumentException("Invalid password"); + } + return jwtUtil.encode(loginUser.getId()); } } diff --git a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java index b97875a2f..a2b062e89 100644 --- a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java +++ b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java @@ -8,8 +8,8 @@ @SuppressWarnings({"InnerClassMayBeStatic", "NonAsciiCharacters"}) @DisplayName("AuthenticationService 클래스") -class AuthenticationServiceTest extends JpaTest{ - private AuthenticationService authenticationService = new AuthenticationService(getUserRepository(), getJwtUtil()); +class AuthenticationServiceTest extends JpaTest { + private final String VALID_TOKEN = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.neCsyNLzy3lQ4o2yliotWT06FwSGZagaHpKdAkjnGGw"; private final String AUTH_NAME = "AUTH_NAME"; @@ -17,7 +17,6 @@ class AuthenticationServiceTest extends JpaTest{ private final String AUTH_PASSWORD = "12345678"; - private UserLoginData AUTH_USER_DATA = UserLoginData.builder() .email(AUTH_EMAIL) .password(AUTH_PASSWORD) @@ -26,8 +25,11 @@ class AuthenticationServiceTest extends JpaTest{ @Nested @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) class login_메서드는 { + private AuthenticationService authenticationService; + @BeforeEach void setUp() { + authenticationService = new AuthenticationService(getUserRepository(), getJwtUtil()); getUserRepository().deleteAll(); getUserRepository().save(User.builder() .name(AUTH_NAME) diff --git a/app/src/test/java/com/codesoom/assignment/application/JpaTest.java b/app/src/test/java/com/codesoom/assignment/application/JpaTest.java index 529501fbc..7569d10d8 100644 --- a/app/src/test/java/com/codesoom/assignment/application/JpaTest.java +++ b/app/src/test/java/com/codesoom/assignment/application/JpaTest.java @@ -7,10 +7,10 @@ @DataJpaTest public class JpaTest { + private final String SECRET = "12345678901234567890123456789010"; + private final JwtUtil jwtUtil = new JwtUtil(SECRET); @Autowired public UserRepository userRepository; - @Autowired - public JwtUtil jwtUtil; public UserRepository getUserRepository() { return userRepository; From dd21842860d229bc676468637a97ebfad17acd06 Mon Sep 17 00:00:00 2001 From: juhyeon Date: Wed, 9 Aug 2023 07:49:02 +0900 Subject: [PATCH 10/36] =?UTF-8?q?chore=20:=20=EA=B0=80=EB=8F=85=EC=84=B1?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20=EB=9D=BC=EC=9D=B8=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/codesoom/assignment/application/JpaTest.java | 1 + .../java/com/codesoom/assignment/utils/JwtUtilTest.java | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/test/java/com/codesoom/assignment/application/JpaTest.java b/app/src/test/java/com/codesoom/assignment/application/JpaTest.java index 7569d10d8..df04c6247 100644 --- a/app/src/test/java/com/codesoom/assignment/application/JpaTest.java +++ b/app/src/test/java/com/codesoom/assignment/application/JpaTest.java @@ -9,6 +9,7 @@ public class JpaTest { private final String SECRET = "12345678901234567890123456789010"; private final JwtUtil jwtUtil = new JwtUtil(SECRET); + @Autowired public UserRepository userRepository; diff --git a/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java b/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java index 89c98a97d..ac260824b 100644 --- a/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java +++ b/app/src/test/java/com/codesoom/assignment/utils/JwtUtilTest.java @@ -1,18 +1,18 @@ package com.codesoom.assignment.utils; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.*; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; @SuppressWarnings({"InnerClassMayBeStatic", "NonAsciiCharacters"}) @DisplayName("JwtUtil 클래스") class JwtUtilTest { private final String SECRET = "12345678901234567890123456789010"; private final String VALID_TOKEN = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.neCsyNLzy3lQ4o2yliotWT06FwSGZagaHpKdAkjnGGw"; - JwtUtil jwtUtil = new JwtUtil(SECRET); private final Long USER_ID = 1L; + + JwtUtil jwtUtil = new JwtUtil(SECRET); @Nested @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @@ -34,7 +34,7 @@ class decode_메서드는 { @Test void It_returns_claims() { assertThat(jwtUtil.decode(VALID_TOKEN)).isNotNull(); - assertThat(jwtUtil.decode(VALID_TOKEN).get("userId",Long.class)).isEqualTo(USER_ID); + assertThat(jwtUtil.decode(VALID_TOKEN).get("userId", Long.class)).isEqualTo(USER_ID); } } } From d94fdbf2bfa190cdca1d1f2c4aa470519c236132 Mon Sep 17 00:00:00 2001 From: juhyeon Date: Wed, 9 Aug 2023 07:49:15 +0900 Subject: [PATCH 11/36] =?UTF-8?q?test=20:=20null=20=EC=B2=B4=ED=81=AC=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assignment/application/AuthenticationServiceTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java index a2b062e89..6e9d07139 100644 --- a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java +++ b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java @@ -42,7 +42,6 @@ void setUp() { @Test void It_returns_token() { String accessToken = authenticationService.login(AUTH_USER_DATA); - Assertions.assertThat(accessToken).isNotNull(); Assertions.assertThat(accessToken).isEqualTo(VALID_TOKEN); } } From 10a47bbb7a6725528ba31f8d2291c479a3ee8b45 Mon Sep 17 00:00:00 2001 From: juhyeon Date: Wed, 9 Aug 2023 08:40:03 +0900 Subject: [PATCH 12/36] =?UTF-8?q?test=20:=20SessionController=20login=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/SessionControllerTest.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 app/src/test/java/com/codesoom/assignment/controllers/SessionControllerTest.java diff --git a/app/src/test/java/com/codesoom/assignment/controllers/SessionControllerTest.java b/app/src/test/java/com/codesoom/assignment/controllers/SessionControllerTest.java new file mode 100644 index 000000000..02284dee2 --- /dev/null +++ b/app/src/test/java/com/codesoom/assignment/controllers/SessionControllerTest.java @@ -0,0 +1,60 @@ +package com.codesoom.assignment.controllers; + +import com.codesoom.assignment.application.AuthenticationService; +import com.codesoom.assignment.dto.UserLoginData; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.*; +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.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import static org.hamcrest.Matchers.containsString; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@AutoConfigureMockMvc +@SuppressWarnings({"InnerClassMayBeStatic", "NonAsciiCharacters"}) +@DisplayName("SessionController 클래스") +class SessionControllerTest { + + private final String VALID_TOKEN = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.neCsyNLzy3lQ4o2yliotWT06FwSGZagaHpKdAkjnGGw"; + private final String AUTH_NAME = "AUTH_NAME"; + private final String AUTH_EMAIL = "auth@foo.com"; + private final String AUTH_PASSWORD = "12345678"; + @Autowired + MockMvc mockMvc; + @Autowired + ObjectMapper objectMapper; + @Autowired + AuthenticationService authenticationService; + private UserLoginData AUTH_USER_DATA = UserLoginData.builder() + .email(AUTH_EMAIL) + .password(AUTH_PASSWORD) + .build(); + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class login_메서드는 { + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 유효한_유저로그인정보_요청를_받으면 { + + @DisplayName("인증토큰을 반환한다.") + @Test + void It_returns_token() throws Exception { + String jsonString = objectMapper.writeValueAsString(AUTH_USER_DATA); + + mockMvc.perform(post("/session") + .contentType(MediaType.APPLICATION_JSON) + .content(jsonString)) + .andExpect(status().isCreated()) + .andExpect(content().string(containsString(VALID_TOKEN))); + } + } + } +} From 267a0671a0852f7cca51e9bfe54874dc93b44f7d Mon Sep 17 00:00:00 2001 From: juhyeon Date: Wed, 9 Aug 2023 08:57:42 +0900 Subject: [PATCH 13/36] =?UTF-8?q?feat=20:=20SessionController=20login=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/SessionController.java | 31 +++++++++++++++++++ .../assignment/dto/SessionResponse.java | 13 ++++++++ 2 files changed, 44 insertions(+) create mode 100644 app/src/main/java/com/codesoom/assignment/controllers/SessionController.java create mode 100644 app/src/main/java/com/codesoom/assignment/dto/SessionResponse.java diff --git a/app/src/main/java/com/codesoom/assignment/controllers/SessionController.java b/app/src/main/java/com/codesoom/assignment/controllers/SessionController.java new file mode 100644 index 000000000..ab067b541 --- /dev/null +++ b/app/src/main/java/com/codesoom/assignment/controllers/SessionController.java @@ -0,0 +1,31 @@ +package com.codesoom.assignment.controllers; + +import com.codesoom.assignment.application.AuthenticationService; +import com.codesoom.assignment.dto.SessionResponse; +import com.codesoom.assignment.dto.UserLoginData; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +@RestController +@RequestMapping("/session") +public class SessionController { + + private final AuthenticationService authenticationService; + + public SessionController(AuthenticationService authenticationService) { + this.authenticationService = authenticationService; + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public SessionResponse login(@RequestBody @Valid UserLoginData userLoginData) { + String accessToken = authenticationService.login(userLoginData); + + return SessionResponse.builder() + .accessToken(accessToken) + .build(); + } + +} diff --git a/app/src/main/java/com/codesoom/assignment/dto/SessionResponse.java b/app/src/main/java/com/codesoom/assignment/dto/SessionResponse.java new file mode 100644 index 000000000..249b63479 --- /dev/null +++ b/app/src/main/java/com/codesoom/assignment/dto/SessionResponse.java @@ -0,0 +1,13 @@ +package com.codesoom.assignment.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +@AllArgsConstructor +public class SessionResponse { + + private String accessToken; +} From 5be4f2229ea05e9e890c95943ab2a84b4dbeb36b Mon Sep 17 00:00:00 2001 From: juhyeon Date: Wed, 9 Aug 2023 08:58:05 +0900 Subject: [PATCH 14/36] =?UTF-8?q?test=20:=20SessionController=20login=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/SessionControllerTest.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/app/src/test/java/com/codesoom/assignment/controllers/SessionControllerTest.java b/app/src/test/java/com/codesoom/assignment/controllers/SessionControllerTest.java index 02284dee2..386f5f754 100644 --- a/app/src/test/java/com/codesoom/assignment/controllers/SessionControllerTest.java +++ b/app/src/test/java/com/codesoom/assignment/controllers/SessionControllerTest.java @@ -5,22 +5,21 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.*; 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.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import static org.hamcrest.Matchers.containsString; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -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; -@SpringBootTest -@AutoConfigureMockMvc +@WebMvcTest(SessionController.class) @SuppressWarnings({"InnerClassMayBeStatic", "NonAsciiCharacters"}) @DisplayName("SessionController 클래스") class SessionControllerTest { - private final String VALID_TOKEN = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.neCsyNLzy3lQ4o2yliotWT06FwSGZagaHpKdAkjnGGw"; private final String AUTH_NAME = "AUTH_NAME"; private final String AUTH_EMAIL = "auth@foo.com"; @@ -29,8 +28,9 @@ class SessionControllerTest { MockMvc mockMvc; @Autowired ObjectMapper objectMapper; - @Autowired + @MockBean AuthenticationService authenticationService; + private UserLoginData AUTH_USER_DATA = UserLoginData.builder() .email(AUTH_EMAIL) .password(AUTH_PASSWORD) @@ -40,10 +40,16 @@ class SessionControllerTest { @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) class login_메서드는 { + @BeforeEach + void setUp() { + given(authenticationService.login(any(UserLoginData.class))) + .willReturn(VALID_TOKEN); + } + @Nested @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) class 유효한_유저로그인정보_요청를_받으면 { - + @DisplayName("인증토큰을 반환한다.") @Test void It_returns_token() throws Exception { @@ -53,7 +59,7 @@ void It_returns_token() throws Exception { .contentType(MediaType.APPLICATION_JSON) .content(jsonString)) .andExpect(status().isCreated()) - .andExpect(content().string(containsString(VALID_TOKEN))); + .andExpect(jsonPath("accessToken").value(VALID_TOKEN)); } } } From 9a97eef817813eee142a4c77b38286d3798a93f8 Mon Sep 17 00:00:00 2001 From: juhyeon Date: Thu, 10 Aug 2023 08:43:55 +0900 Subject: [PATCH 15/36] =?UTF-8?q?test=20:=20AuthenticationService=20?= =?UTF-8?q?=EC=84=B1=EA=B3=B5=EC=BC=80=EC=9D=B4=EC=8A=A4=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EC=9D=B4=EC=99=B8=EC=9D=98=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=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 AuthenticationService 의 테스트에는 해피테스트만 존재하는 상태이므로 존재하지 않은 유저의 요청정보가 오는 경우의 테스트 추가 --- .../AuthenticationServiceTest.java | 48 +++++++++++++------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java index 6e9d07139..0ef6495d5 100644 --- a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java +++ b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java @@ -27,22 +27,42 @@ class AuthenticationServiceTest extends JpaTest { class login_메서드는 { private AuthenticationService authenticationService; - @BeforeEach - void setUp() { - authenticationService = new AuthenticationService(getUserRepository(), getJwtUtil()); - getUserRepository().deleteAll(); - getUserRepository().save(User.builder() - .name(AUTH_NAME) - .email(AUTH_EMAIL) - .password(AUTH_PASSWORD) - .build()); + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 유효한_유저로그인정보_요청를_받으면 { + @BeforeEach + void setUp() { + authenticationService = new AuthenticationService(getUserRepository(), getJwtUtil()); + getUserRepository().deleteAll(); + getUserRepository().save(User.builder() + .name(AUTH_NAME) + .email(AUTH_EMAIL) + .password(AUTH_PASSWORD) + .build()); + } + + @DisplayName("인증토큰을 반환한다.") + @Test + void It_returns_token() { + String accessToken = authenticationService.login(AUTH_USER_DATA); + Assertions.assertThat(accessToken).isEqualTo(VALID_TOKEN); + } + } - @DisplayName("유저로그인정보를 받아 인증토큰을 반환한다.") - @Test - void It_returns_token() { - String accessToken = authenticationService.login(AUTH_USER_DATA); - Assertions.assertThat(accessToken).isEqualTo(VALID_TOKEN); + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 유효하지_않은_로그인정보를_받으면 { + private UserLoginData IS_NOT_EXISTS_USER_DATA = UserLoginData.builder() + .email("InvalidEmail") + .password(AUTH_PASSWORD).build(); + + @DisplayName("해당 정보의 회원이 존재하지 않으면 UserNotFoundException을 반환한다.") + @Test + void It_throws_UserNotFoundException() { + Assertions.assertThatThrownBy(() -> authenticationService.login(IS_NOT_EXISTS_USER_DATA)); + } } + } } From b4b09c1dd3eb350d376e9648329bbc6993433ef5 Mon Sep 17 00:00:00 2001 From: juhyeon Date: Thu, 10 Aug 2023 08:48:44 +0900 Subject: [PATCH 16/36] =?UTF-8?q?feat=20:=20AuthenticationService=20?= =?UTF-8?q?=EC=A1=B4=EC=9E=AC=ED=95=98=EC=A7=80=EC=95=8A=EB=8A=94=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EC=8B=9C=20=EC=B2=98=EB=A6=AC=20=EA=B8=B0?= =?UTF-8?q?=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 자바의 IllegalArgumentException을 발생시키는 예외처리에서 커스텀 예외인 UserNotFoundException으로 명시적으로 예외를 던져주기 위해 UserNotFoundException의 생성자로 Email을 받아 해당 메시지를 표시하도록 수정하였습니다. --- .../assignment/application/AuthenticationService.java | 3 ++- .../com/codesoom/assignment/errors/UserNotFoundException.java | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/codesoom/assignment/application/AuthenticationService.java b/app/src/main/java/com/codesoom/assignment/application/AuthenticationService.java index aa1bd831e..93eca0bb0 100644 --- a/app/src/main/java/com/codesoom/assignment/application/AuthenticationService.java +++ b/app/src/main/java/com/codesoom/assignment/application/AuthenticationService.java @@ -3,6 +3,7 @@ import com.codesoom.assignment.domain.User; import com.codesoom.assignment.domain.UserRepository; import com.codesoom.assignment.dto.UserLoginData; +import com.codesoom.assignment.errors.UserNotFoundException; import com.codesoom.assignment.utils.JwtUtil; import org.springframework.stereotype.Service; @@ -18,7 +19,7 @@ public AuthenticationService(UserRepository userRepository, JwtUtil jwtUtil) { public String login(UserLoginData loginData) { User loginUser = userRepository.findByEmail(loginData.getEmail()) - .orElseThrow(() -> new IllegalArgumentException("Invalid email address")); + .orElseThrow(() -> new UserNotFoundException(loginData.getEmail())); if (!loginUser.getPassword().equals(loginData.getPassword())) { throw new IllegalArgumentException("Invalid password"); diff --git a/app/src/main/java/com/codesoom/assignment/errors/UserNotFoundException.java b/app/src/main/java/com/codesoom/assignment/errors/UserNotFoundException.java index 870dfd123..b4a65e7b7 100644 --- a/app/src/main/java/com/codesoom/assignment/errors/UserNotFoundException.java +++ b/app/src/main/java/com/codesoom/assignment/errors/UserNotFoundException.java @@ -4,4 +4,8 @@ public class UserNotFoundException extends RuntimeException { public UserNotFoundException(Long id) { super("User not found: " + id); } + + public UserNotFoundException(String email) { + super("User not found: " + email); + } } From b569da829abda2209eec84796ff26c6132ea4eb3 Mon Sep 17 00:00:00 2001 From: juhyeon Date: Thu, 10 Aug 2023 08:54:04 +0900 Subject: [PATCH 17/36] =?UTF-8?q?chore=20:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=8B=9C=20authenticationService=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9D=B4=EC=8A=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 예외테스트 시 authenticationService가 생성하지 않아서 상위레벨에서 할당하도록 변경 --- .../assignment/application/AuthenticationServiceTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java index 0ef6495d5..778f9740e 100644 --- a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java +++ b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java @@ -2,6 +2,7 @@ import com.codesoom.assignment.domain.User; import com.codesoom.assignment.dto.UserLoginData; +import com.codesoom.assignment.errors.UserNotFoundException; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.*; @@ -25,14 +26,13 @@ class AuthenticationServiceTest extends JpaTest { @Nested @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) class login_메서드는 { - private AuthenticationService authenticationService; + private AuthenticationService authenticationService = new AuthenticationService(getUserRepository(), getJwtUtil()); @Nested @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) class 유효한_유저로그인정보_요청를_받으면 { @BeforeEach void setUp() { - authenticationService = new AuthenticationService(getUserRepository(), getJwtUtil()); getUserRepository().deleteAll(); getUserRepository().save(User.builder() .name(AUTH_NAME) @@ -60,7 +60,7 @@ class 유효하지_않은_로그인정보를_받으면 { @DisplayName("해당 정보의 회원이 존재하지 않으면 UserNotFoundException을 반환한다.") @Test void It_throws_UserNotFoundException() { - Assertions.assertThatThrownBy(() -> authenticationService.login(IS_NOT_EXISTS_USER_DATA)); + Assertions.assertThatThrownBy(() -> authenticationService.login(IS_NOT_EXISTS_USER_DATA)).isInstanceOf(UserNotFoundException.class); } } From f5bb2b4d28b25200666f4354c40ed92c6ad82962 Mon Sep 17 00:00:00 2001 From: juhyeon Date: Fri, 11 Aug 2023 07:56:11 +0900 Subject: [PATCH 18/36] =?UTF-8?q?chore=20:=20authenticationService=20?= =?UTF-8?q?=ED=94=BD=EC=8A=A4=EC=B3=90=20=EC=9C=84=EC=B9=98=20=EA=B0=81=20?= =?UTF-8?q?=ED=95=B4=EB=8B=B9=20=EC=BB=A8=ED=85=8D=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 픽스쳐 위치가 상위 컨텍스트에 공통으로 있는 부분 컨텍스트에 있는 부분 통일 되지 않아서 각 테스트 문맥에 맞도록 픽스쳐 위치 이동 하였습니다 --- .../application/AuthenticationServiceTest.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java index 778f9740e..eb3ecf5d5 100644 --- a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java +++ b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java @@ -15,22 +15,24 @@ class AuthenticationServiceTest extends JpaTest { private final String AUTH_NAME = "AUTH_NAME"; private final String AUTH_EMAIL = "auth@foo.com"; + private final String INVALID_EMAIL = AUTH_EMAIL + "INVALID"; private final String AUTH_PASSWORD = "12345678"; - private UserLoginData AUTH_USER_DATA = UserLoginData.builder() - .email(AUTH_EMAIL) - .password(AUTH_PASSWORD) - .build(); - @Nested @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) class login_메서드는 { private AuthenticationService authenticationService = new AuthenticationService(getUserRepository(), getJwtUtil()); + @Nested @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) class 유효한_유저로그인정보_요청를_받으면 { + private UserLoginData AUTH_USER_DATA = UserLoginData.builder() + .email(AUTH_EMAIL) + .password(AUTH_PASSWORD) + .build(); + @BeforeEach void setUp() { getUserRepository().deleteAll(); @@ -54,7 +56,7 @@ void It_returns_token() { @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) class 유효하지_않은_로그인정보를_받으면 { private UserLoginData IS_NOT_EXISTS_USER_DATA = UserLoginData.builder() - .email("InvalidEmail") + .email(INVALID_EMAIL) .password(AUTH_PASSWORD).build(); @DisplayName("해당 정보의 회원이 존재하지 않으면 UserNotFoundException을 반환한다.") From b32fd9bc0cf022d6f75704ab151412eef549d325 Mon Sep 17 00:00:00 2001 From: juhyeon Date: Fri, 11 Aug 2023 08:07:34 +0900 Subject: [PATCH 19/36] =?UTF-8?q?test=20:=20authenticationService=20?= =?UTF-8?q?=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20=EC=9D=BC=EC=B9=98=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=EC=B2=98=EB=A6=AC=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 비밀번호가 일치하지 않은 경우 예외 테스트가 존재하지않아 추가 --- .../application/AuthenticationServiceTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java index eb3ecf5d5..6b41dd226 100644 --- a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java +++ b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java @@ -2,6 +2,7 @@ import com.codesoom.assignment.domain.User; import com.codesoom.assignment.dto.UserLoginData; +import com.codesoom.assignment.errors.InvalidLoginException; import com.codesoom.assignment.errors.UserNotFoundException; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.*; @@ -17,6 +18,7 @@ class AuthenticationServiceTest extends JpaTest { private final String AUTH_EMAIL = "auth@foo.com"; private final String INVALID_EMAIL = AUTH_EMAIL + "INVALID"; private final String AUTH_PASSWORD = "12345678"; + private final String INVALID_PASSWORD = AUTH_PASSWORD + "INVALID"; @Nested @@ -59,11 +61,22 @@ class 유효하지_않은_로그인정보를_받으면 { .email(INVALID_EMAIL) .password(AUTH_PASSWORD).build(); + private UserLoginData INVALID_PASSWORD_USER_DATA = UserLoginData.builder() + .email(AUTH_EMAIL) + .password(INVALID_PASSWORD) + .build(); + @DisplayName("해당 정보의 회원이 존재하지 않으면 UserNotFoundException을 반환한다.") @Test void It_throws_UserNotFoundException() { Assertions.assertThatThrownBy(() -> authenticationService.login(IS_NOT_EXISTS_USER_DATA)).isInstanceOf(UserNotFoundException.class); } + + @DisplayName("비밀번호가 일치하지 않으면 InvalidLoginException을 반환한다.") + @Test + void It_throws_InvalidLoginRequest() { + Assertions.assertThatThrownBy(() -> authenticationService.login(INVALID_PASSWORD_USER_DATA)).isInstanceOf(InvalidLoginException.class); + } } } From b5152774dbf18734921e3dc84ea320f635ac2fef Mon Sep 17 00:00:00 2001 From: juhyeon Date: Fri, 11 Aug 2023 08:17:06 +0900 Subject: [PATCH 20/36] =?UTF-8?q?feat=20:=20authenticationService=20?= =?UTF-8?q?=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20=EC=9D=BC=EC=B9=98=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=EC=B2=98=EB=A6=AC=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 비밀번호가 일치하지 않은 경우 예외처리가 기본 IllegalArgumentException 을 사용하여 명확하지 않은 모호하므로 커스텀에러를 추가 --- .../assignment/application/AuthenticationService.java | 3 ++- .../assignment/controllers/ControllerErrorAdvice.java | 7 +++++++ .../codesoom/assignment/errors/InvalidLoginException.java | 8 ++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/codesoom/assignment/errors/InvalidLoginException.java diff --git a/app/src/main/java/com/codesoom/assignment/application/AuthenticationService.java b/app/src/main/java/com/codesoom/assignment/application/AuthenticationService.java index 93eca0bb0..d54a0ece6 100644 --- a/app/src/main/java/com/codesoom/assignment/application/AuthenticationService.java +++ b/app/src/main/java/com/codesoom/assignment/application/AuthenticationService.java @@ -3,6 +3,7 @@ import com.codesoom.assignment.domain.User; import com.codesoom.assignment.domain.UserRepository; import com.codesoom.assignment.dto.UserLoginData; +import com.codesoom.assignment.errors.InvalidLoginException; import com.codesoom.assignment.errors.UserNotFoundException; import com.codesoom.assignment.utils.JwtUtil; import org.springframework.stereotype.Service; @@ -22,7 +23,7 @@ public String login(UserLoginData loginData) { .orElseThrow(() -> new UserNotFoundException(loginData.getEmail())); if (!loginUser.getPassword().equals(loginData.getPassword())) { - throw new IllegalArgumentException("Invalid password"); + throw new InvalidLoginException("Check your password"); } return jwtUtil.encode(loginUser.getId()); } diff --git a/app/src/main/java/com/codesoom/assignment/controllers/ControllerErrorAdvice.java b/app/src/main/java/com/codesoom/assignment/controllers/ControllerErrorAdvice.java index 099939d4e..0c7fb40e6 100644 --- a/app/src/main/java/com/codesoom/assignment/controllers/ControllerErrorAdvice.java +++ b/app/src/main/java/com/codesoom/assignment/controllers/ControllerErrorAdvice.java @@ -1,6 +1,7 @@ package com.codesoom.assignment.controllers; import com.codesoom.assignment.dto.ErrorResponse; +import com.codesoom.assignment.errors.InvalidLoginException; import com.codesoom.assignment.errors.ProductNotFoundException; import com.codesoom.assignment.errors.UserEmailDuplicationException; import com.codesoom.assignment.errors.UserNotFoundException; @@ -30,4 +31,10 @@ public ErrorResponse handleUserNotFound() { public ErrorResponse handleUserEmailIsAlreadyExisted() { return new ErrorResponse("User's email address is already existed"); } + + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(InvalidLoginException.class) + public ErrorResponse handleInvalidLogin() { + return new ErrorResponse("Invalid login request"); + } } diff --git a/app/src/main/java/com/codesoom/assignment/errors/InvalidLoginException.java b/app/src/main/java/com/codesoom/assignment/errors/InvalidLoginException.java new file mode 100644 index 000000000..9809f0c93 --- /dev/null +++ b/app/src/main/java/com/codesoom/assignment/errors/InvalidLoginException.java @@ -0,0 +1,8 @@ +package com.codesoom.assignment.errors; + +public class InvalidLoginException extends RuntimeException { + public InvalidLoginException(String message) { + super("Invalid login Exception: " + message); + } + +} From d89b578cc0385dcac03f0cd991a08b9ddc4e9ee6 Mon Sep 17 00:00:00 2001 From: juhyeon Date: Fri, 11 Aug 2023 08:19:39 +0900 Subject: [PATCH 21/36] =?UTF-8?q?chore=20:=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=98=88=EC=99=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=EC=A0=84=EC=B2=98=EB=A6=AC=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 비밀번호가 일치하지 않은 경우를 체크하려면 해당 유저가 존재해야 하므로 해당 정보를 미리 넣어 두도록 수정 --- .../application/AuthenticationServiceTest.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java index 6b41dd226..98e3021a9 100644 --- a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java +++ b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java @@ -60,12 +60,21 @@ class 유효하지_않은_로그인정보를_받으면 { private UserLoginData IS_NOT_EXISTS_USER_DATA = UserLoginData.builder() .email(INVALID_EMAIL) .password(AUTH_PASSWORD).build(); - private UserLoginData INVALID_PASSWORD_USER_DATA = UserLoginData.builder() .email(AUTH_EMAIL) .password(INVALID_PASSWORD) .build(); + @BeforeEach + void setUp() { + getUserRepository().deleteAll(); + getUserRepository().save(User.builder() + .name(AUTH_NAME) + .email(AUTH_EMAIL) + .password(AUTH_PASSWORD) + .build()); + } + @DisplayName("해당 정보의 회원이 존재하지 않으면 UserNotFoundException을 반환한다.") @Test void It_throws_UserNotFoundException() { From 66aa167ba514c71f564956624fea3ddd193aa402 Mon Sep 17 00:00:00 2001 From: tmxhsk99 Date: Sat, 12 Aug 2023 08:06:34 +0900 Subject: [PATCH 22/36] =?UTF-8?q?refactor=20:=20TestHelper=EB=A1=9C=20?= =?UTF-8?q?=ED=94=BD=EC=8A=A4=EC=B2=98=20=EB=A6=AC=ED=8C=A9=ED=84=B0?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 테스트용 픽스처가 테스트코드와 함께 존재하는 상태에서 TestHelper 코드에 픽스쳐 분리하여 리팩터링 --- .../AuthenticationServiceTest.java | 29 +++------------ .../codesoom/assignment/utils/TestHelper.java | 35 +++++++++++++++++++ 2 files changed, 40 insertions(+), 24 deletions(-) create mode 100644 app/src/test/java/com/codesoom/assignment/utils/TestHelper.java diff --git a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java index 98e3021a9..39910001f 100644 --- a/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java +++ b/app/src/test/java/com/codesoom/assignment/application/AuthenticationServiceTest.java @@ -4,21 +4,17 @@ import com.codesoom.assignment.dto.UserLoginData; import com.codesoom.assignment.errors.InvalidLoginException; import com.codesoom.assignment.errors.UserNotFoundException; +import com.codesoom.assignment.utils.TestHelper; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.*; +import static com.codesoom.assignment.utils.TestHelper.*; + @SuppressWarnings({"InnerClassMayBeStatic", "NonAsciiCharacters"}) @DisplayName("AuthenticationService 클래스") class AuthenticationServiceTest extends JpaTest { - private final String VALID_TOKEN = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.neCsyNLzy3lQ4o2yliotWT06FwSGZagaHpKdAkjnGGw"; - - private final String AUTH_NAME = "AUTH_NAME"; - private final String AUTH_EMAIL = "auth@foo.com"; - private final String INVALID_EMAIL = AUTH_EMAIL + "INVALID"; - private final String AUTH_PASSWORD = "12345678"; - private final String INVALID_PASSWORD = AUTH_PASSWORD + "INVALID"; @Nested @@ -38,11 +34,7 @@ class 유효한_유저로그인정보_요청를_받으면 { @BeforeEach void setUp() { getUserRepository().deleteAll(); - getUserRepository().save(User.builder() - .name(AUTH_NAME) - .email(AUTH_EMAIL) - .password(AUTH_PASSWORD) - .build()); + getUserRepository().save(AUTH_USER); } @DisplayName("인증토큰을 반환한다.") @@ -57,22 +49,11 @@ void It_returns_token() { @Nested @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) class 유효하지_않은_로그인정보를_받으면 { - private UserLoginData IS_NOT_EXISTS_USER_DATA = UserLoginData.builder() - .email(INVALID_EMAIL) - .password(AUTH_PASSWORD).build(); - private UserLoginData INVALID_PASSWORD_USER_DATA = UserLoginData.builder() - .email(AUTH_EMAIL) - .password(INVALID_PASSWORD) - .build(); @BeforeEach void setUp() { getUserRepository().deleteAll(); - getUserRepository().save(User.builder() - .name(AUTH_NAME) - .email(AUTH_EMAIL) - .password(AUTH_PASSWORD) - .build()); + getUserRepository().save(AUTH_USER); } @DisplayName("해당 정보의 회원이 존재하지 않으면 UserNotFoundException을 반환한다.") diff --git a/app/src/test/java/com/codesoom/assignment/utils/TestHelper.java b/app/src/test/java/com/codesoom/assignment/utils/TestHelper.java new file mode 100644 index 000000000..dc41efe80 --- /dev/null +++ b/app/src/test/java/com/codesoom/assignment/utils/TestHelper.java @@ -0,0 +1,35 @@ +package com.codesoom.assignment.utils; + +import com.codesoom.assignment.domain.User; +import com.codesoom.assignment.dto.UserLoginData; + +public class TestHelper { + + public static final String VALID_TOKEN = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.neCsyNLzy3lQ4o2yliotWT06FwSGZagaHpKdAkjnGGw"; + public static final String AUTH_NAME = "AUTH_NAME"; + public static final String AUTH_EMAIL = "auth@foo.com"; + public static final String INVALID_EMAIL = AUTH_EMAIL + "INVALID"; + public static final String AUTH_PASSWORD = "12345678"; + public static final String INVALID_PASSWORD = AUTH_PASSWORD + "INVALID"; + + public static UserLoginData AUTH_USER_DATA = UserLoginData.builder() + .email(AUTH_EMAIL) + .password(AUTH_PASSWORD) + .build(); + + public static User AUTH_USER = User.builder() + .name(AUTH_NAME) + .email(AUTH_EMAIL) + .password(AUTH_PASSWORD) + .build(); + + + public static UserLoginData IS_NOT_EXISTS_USER_DATA = UserLoginData.builder() + .email(INVALID_EMAIL) + .password(AUTH_PASSWORD).build(); + + public static UserLoginData INVALID_PASSWORD_USER_DATA = UserLoginData.builder() + .email(AUTH_EMAIL) + .password(INVALID_PASSWORD) + .build(); +} From ac22ea0f659684bdf876f348a39edcfe8d4a3738 Mon Sep 17 00:00:00 2001 From: tmxhsk99 Date: Sat, 12 Aug 2023 13:45:57 +0900 Subject: [PATCH 23/36] =?UTF-8?q?refactor=20:=20SessionControllerTest=20?= =?UTF-8?q?=ED=94=BD=EC=8A=A4=EC=B3=90=20TestHelper=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SessionControllerTest의 픽스쳐도 TestHelper로 대체 가능한 부분이 있기때문에 해당 부분 TestHelper 사용으로 대체 --- .../assignment/controllers/SessionControllerTest.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/test/java/com/codesoom/assignment/controllers/SessionControllerTest.java b/app/src/test/java/com/codesoom/assignment/controllers/SessionControllerTest.java index 386f5f754..16ae53100 100644 --- a/app/src/test/java/com/codesoom/assignment/controllers/SessionControllerTest.java +++ b/app/src/test/java/com/codesoom/assignment/controllers/SessionControllerTest.java @@ -10,6 +10,7 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; +import static com.codesoom.assignment.utils.TestHelper.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -20,10 +21,7 @@ @SuppressWarnings({"InnerClassMayBeStatic", "NonAsciiCharacters"}) @DisplayName("SessionController 클래스") class SessionControllerTest { - private final String VALID_TOKEN = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.neCsyNLzy3lQ4o2yliotWT06FwSGZagaHpKdAkjnGGw"; - private final String AUTH_NAME = "AUTH_NAME"; - private final String AUTH_EMAIL = "auth@foo.com"; - private final String AUTH_PASSWORD = "12345678"; + @Autowired MockMvc mockMvc; @Autowired From abefd61f8a0d043873bb906f1ccd42b5aa54ae40 Mon Sep 17 00:00:00 2001 From: tmxhsk99 Date: Sat, 12 Aug 2023 17:58:33 +0900 Subject: [PATCH 24/36] =?UTF-8?q?test=20:=20AuthInterceptor=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20TestHelpe?= =?UTF-8?q?r=EC=97=90=20=EA=B4=80=EB=A0=A8=20=ED=94=BD=EC=8A=A4=EC=B3=90?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interceptor/AuthInterceptorTest.java | 42 ++++++++++++ .../codesoom/assignment/utils/TestHelper.java | 67 ++++++++++++++++--- 2 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 app/src/test/java/com/codesoom/assignment/interceptor/AuthInterceptorTest.java diff --git a/app/src/test/java/com/codesoom/assignment/interceptor/AuthInterceptorTest.java b/app/src/test/java/com/codesoom/assignment/interceptor/AuthInterceptorTest.java new file mode 100644 index 000000000..969f756b1 --- /dev/null +++ b/app/src/test/java/com/codesoom/assignment/interceptor/AuthInterceptorTest.java @@ -0,0 +1,42 @@ +package com.codesoom.assignment.interceptor; + +import com.codesoom.assignment.application.JpaTest; +import com.codesoom.assignment.errors.AccessTokenNotFoundException; +import com.codesoom.assignment.errors.InvalidAccessTokenException; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.*; + +import static com.codesoom.assignment.utils.TestHelper.*; + +@SuppressWarnings({"InnerClassMayBeStatic", "NonAsciiCharacters"}) +@DisplayName("AuthInterceptor 클래스") +class AuthInterceptorTest extends JpaTest { + AuthInterceptor authInterceptor = new AuthInterceptor(getJwtUtil()); + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class preHandle_메서드는 { + + @DisplayName("인증토큰이 없으면 AccessTokenNotFoundException을 반환한다.") + @Test + void It_returns_AccessTokenNotFoundException() { + Assertions.assertThatThrownBy(() -> authInterceptor.preHandle(INVALID_SERVLET_REQUEST, null, null)) + .isInstanceOf(AccessTokenNotFoundException.class); + } + + @DisplayName("인증토큰이 유효하지 않으면 InvalidAccessTokenException을 반환한다.") + @Test + void It_returns_InvalidAccessTokenException() { + Assertions.assertThatThrownBy(() -> authInterceptor.preHandle(getInvalidTokenServletRequest(), null, null)) + .isInstanceOf(InvalidAccessTokenException.class); + } + + @DisplayName("인증토큰이 유효하면 true를 반환한다.") + @Test + void It_returns_true() throws Exception { + Assertions.assertThat(authInterceptor.preHandle(getValidTokenServletRequest(), null, null)) + .isTrue(); + } + } + +} diff --git a/app/src/test/java/com/codesoom/assignment/utils/TestHelper.java b/app/src/test/java/com/codesoom/assignment/utils/TestHelper.java index dc41efe80..ed053bcd5 100644 --- a/app/src/test/java/com/codesoom/assignment/utils/TestHelper.java +++ b/app/src/test/java/com/codesoom/assignment/utils/TestHelper.java @@ -1,35 +1,86 @@ package com.codesoom.assignment.utils; +import com.codesoom.assignment.domain.Product; import com.codesoom.assignment.domain.User; +import com.codesoom.assignment.dto.ProductData; import com.codesoom.assignment.dto.UserLoginData; +import org.junit.jupiter.params.provider.Arguments; +import org.springframework.mock.web.MockHttpServletRequest; + +import java.util.stream.Stream; public class TestHelper { public static final String VALID_TOKEN = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.neCsyNLzy3lQ4o2yliotWT06FwSGZagaHpKdAkjnGGw"; + public static final String INVALID_TOKEN = VALID_TOKEN + "INVALID"; public static final String AUTH_NAME = "AUTH_NAME"; public static final String AUTH_EMAIL = "auth@foo.com"; public static final String INVALID_EMAIL = AUTH_EMAIL + "INVALID"; public static final String AUTH_PASSWORD = "12345678"; + public static final String TEST_PRODUCT_NAME = "쥐돌이"; + public static final String TEST_UPDATE_PRODUCT_NAME = "쥐순이"; + public static final String TEST_PRODUCT_MAKER = "냥이월드"; + public static final int TEST_PRODUCT_PRICE = 5000; public static final String INVALID_PASSWORD = AUTH_PASSWORD + "INVALID"; + public static final MockHttpServletRequest INVALID_SERVLET_REQUEST = new MockHttpServletRequest(); - public static UserLoginData AUTH_USER_DATA = UserLoginData.builder() + public static final UserLoginData IS_NOT_EXISTS_USER_DATA = UserLoginData.builder() + .email(INVALID_EMAIL) + .password(AUTH_PASSWORD).build(); + + public static final UserLoginData INVALID_PASSWORD_USER_DATA = UserLoginData.builder() + .email(AUTH_EMAIL) + .password(INVALID_PASSWORD) + .build(); + + public static final UserLoginData AUTH_USER_DATA = UserLoginData.builder() .email(AUTH_EMAIL) .password(AUTH_PASSWORD) .build(); - public static User AUTH_USER = User.builder() + public static final User AUTH_USER = User.builder() .name(AUTH_NAME) .email(AUTH_EMAIL) .password(AUTH_PASSWORD) .build(); + public static final Product TEST_PRODUCT = Product.builder() + .id(1L) + .name(TEST_PRODUCT_NAME) + .maker(TEST_PRODUCT_MAKER) + .price(TEST_PRODUCT_PRICE) + .build(); - public static UserLoginData IS_NOT_EXISTS_USER_DATA = UserLoginData.builder() - .email(INVALID_EMAIL) - .password(AUTH_PASSWORD).build(); + public static final ProductData TEST_PRODUCT_DATA = ProductData.builder() + .name(TEST_PRODUCT_NAME) + .maker(TEST_PRODUCT_MAKER) + .price(TEST_PRODUCT_PRICE) + .build(); - public static UserLoginData INVALID_PASSWORD_USER_DATA = UserLoginData.builder() - .email(AUTH_EMAIL) - .password(INVALID_PASSWORD) + public static Stream provideInvalidProductRequests() { + return Stream.of( + Arguments.of(ProductData.builder().name("").maker("").price(0).build()), + Arguments.of(ProductData.builder().name("").maker(TEST_PRODUCT_MAKER).price(TEST_PRODUCT_PRICE).build()), + Arguments.of(ProductData.builder().name(TEST_PRODUCT_NAME).maker("").price(TEST_PRODUCT_PRICE).build()), + Arguments.of(ProductData.builder().name(TEST_PRODUCT_NAME).maker(TEST_PRODUCT_MAKER).price(null).build()) + ); + } + + public static final ProductData UPDATE_PRODUCT_DATA = ProductData.builder() + .name(TEST_UPDATE_PRODUCT_NAME) + .maker(TEST_PRODUCT_MAKER) + .price(TEST_PRODUCT_PRICE) .build(); + + public static MockHttpServletRequest getInvalidTokenServletRequest() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader("Authorization", "Bearer " + INVALID_TOKEN); + return request; + } + + public static MockHttpServletRequest getValidTokenServletRequest() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader("Authorization", "Bearer " + VALID_TOKEN); + return request; + } } From 019b774f6093260a21de13d600fdce462283674a Mon Sep 17 00:00:00 2001 From: tmxhsk99 Date: Sat, 12 Aug 2023 17:59:38 +0900 Subject: [PATCH 25/36] =?UTF-8?q?feat=20:=20product=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20=EC=9D=B8=EC=A6=9D=20=EC=B2=98=EB=A6=AC=EB=A5=BC=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20AuthInterceptor=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interceptor/AuthInterceptor.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java diff --git a/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java b/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java new file mode 100644 index 000000000..49ab90dcd --- /dev/null +++ b/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java @@ -0,0 +1,34 @@ +package com.codesoom.assignment.interceptor; + +import com.codesoom.assignment.errors.AccessTokenNotFoundException; +import com.codesoom.assignment.errors.InvalidAccessTokenException; +import com.codesoom.assignment.utils.JwtUtil; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@Component +public class AuthInterceptor implements HandlerInterceptor { + + private final JwtUtil jwtUtil; + + public AuthInterceptor(JwtUtil jwtUtil) { + this.jwtUtil = jwtUtil; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + + String authorization = request.getHeader("Authorization"); + if (authorization == null) throw new AccessTokenNotFoundException(); + String accessToken = authorization.substring("Bearer ".length()); + try { + jwtUtil.decode(accessToken); + } catch (Exception e) { + throw new InvalidAccessTokenException(e.getMessage()); + } + return true; + } +} From 1839623329670d7edbdf95a3ad0cb5d4f754bfd8 Mon Sep 17 00:00:00 2001 From: tmxhsk99 Date: Sat, 12 Aug 2023 18:01:08 +0900 Subject: [PATCH 26/36] =?UTF-8?q?feat=20:=20=EC=9D=B8=EC=A6=9D=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=EC=8B=9C=20=EB=B0=9C=EC=83=9D=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EC=BB=A4=EC=8A=A4=ED=85=80=20=EC=97=90=EB=9F=AC=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 AccessTokenNotFoundException(인증토큰 없음 예외) InvalidAccessTokenException(인증토큰 유효성 예외) --- .../errors/AccessTokenNotFoundException.java | 8 ++++++++ .../errors/InvalidAccessTokenException.java | 14 ++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 app/src/main/java/com/codesoom/assignment/errors/AccessTokenNotFoundException.java create mode 100644 app/src/main/java/com/codesoom/assignment/errors/InvalidAccessTokenException.java diff --git a/app/src/main/java/com/codesoom/assignment/errors/AccessTokenNotFoundException.java b/app/src/main/java/com/codesoom/assignment/errors/AccessTokenNotFoundException.java new file mode 100644 index 000000000..1579813bd --- /dev/null +++ b/app/src/main/java/com/codesoom/assignment/errors/AccessTokenNotFoundException.java @@ -0,0 +1,8 @@ +package com.codesoom.assignment.errors; + +public class AccessTokenNotFoundException extends RuntimeException { + + public AccessTokenNotFoundException() { + super("Access token not found"); + } +} diff --git a/app/src/main/java/com/codesoom/assignment/errors/InvalidAccessTokenException.java b/app/src/main/java/com/codesoom/assignment/errors/InvalidAccessTokenException.java new file mode 100644 index 000000000..8216143a2 --- /dev/null +++ b/app/src/main/java/com/codesoom/assignment/errors/InvalidAccessTokenException.java @@ -0,0 +1,14 @@ +package com.codesoom.assignment.errors; + +public class InvalidAccessTokenException extends RuntimeException { + + public InvalidAccessTokenException(String message) { + super("Invalid access token : " + message); + } + + public InvalidAccessTokenException() { + super("Invalid access token"); + } + + +} From 9fd2f24fd9d972535b1cb987aff93c7f9f63623c Mon Sep 17 00:00:00 2001 From: tmxhsk99 Date: Sat, 12 Aug 2023 18:02:49 +0900 Subject: [PATCH 27/36] =?UTF-8?q?feat=20:=20=EC=BB=A4=EC=8A=A4=ED=85=80=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=EC=B6=94=EA=B0=80=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20=EC=97=90=EB=9F=AC=EC=B2=98=EB=A6=AC=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 --- .../controllers/ControllerErrorAdvice.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/codesoom/assignment/controllers/ControllerErrorAdvice.java b/app/src/main/java/com/codesoom/assignment/controllers/ControllerErrorAdvice.java index 0c7fb40e6..7c7939142 100644 --- a/app/src/main/java/com/codesoom/assignment/controllers/ControllerErrorAdvice.java +++ b/app/src/main/java/com/codesoom/assignment/controllers/ControllerErrorAdvice.java @@ -1,10 +1,7 @@ package com.codesoom.assignment.controllers; import com.codesoom.assignment.dto.ErrorResponse; -import com.codesoom.assignment.errors.InvalidLoginException; -import com.codesoom.assignment.errors.ProductNotFoundException; -import com.codesoom.assignment.errors.UserEmailDuplicationException; -import com.codesoom.assignment.errors.UserNotFoundException; +import com.codesoom.assignment.errors.*; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -37,4 +34,16 @@ public ErrorResponse handleUserEmailIsAlreadyExisted() { public ErrorResponse handleInvalidLogin() { return new ErrorResponse("Invalid login request"); } + + @ResponseStatus(HttpStatus.UNAUTHORIZED) + @ExceptionHandler(AccessTokenNotFoundException.class) + public ErrorResponse handleAccessTokenNotFound() { + return new ErrorResponse("Access token not found"); + } + + @ResponseStatus(HttpStatus.UNAUTHORIZED) + @ExceptionHandler(InvalidAccessTokenException.class) + public ErrorResponse handleInvalidAccessToken() { + return new ErrorResponse("Invalid access token"); + } } From 0e17692828b59476168f2a9cc3f3922f96b0f881 Mon Sep 17 00:00:00 2001 From: tmxhsk99 Date: Sat, 12 Aug 2023 18:23:37 +0900 Subject: [PATCH 28/36] =?UTF-8?q?feat=20:=20=EC=9D=B8=ED=84=B0=EC=85=89?= =?UTF-8?q?=ED=84=B0=20=EC=A0=81=EC=9A=A9=20=EB=B0=8F=20=EC=9A=94=EC=B2=AD?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EA=B2=80=EC=A6=9D=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../codesoom/assignment/config/WebConfig.java | 20 ++++++++++++++ .../interceptor/AuthInterceptor.java | 26 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 app/src/main/java/com/codesoom/assignment/config/WebConfig.java diff --git a/app/src/main/java/com/codesoom/assignment/config/WebConfig.java b/app/src/main/java/com/codesoom/assignment/config/WebConfig.java new file mode 100644 index 000000000..92d78eb52 --- /dev/null +++ b/app/src/main/java/com/codesoom/assignment/config/WebConfig.java @@ -0,0 +1,20 @@ +package com.codesoom.assignment.config; + +import com.codesoom.assignment.interceptor.AuthInterceptor; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +public class WebConfig implements WebMvcConfigurer { + private final AuthInterceptor authInterceptor; + + public WebConfig(AuthInterceptor authInterceptor) { + this.authInterceptor = authInterceptor; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(authInterceptor) + .addPathPatterns("/products"); + } + +} diff --git a/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java b/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java index 49ab90dcd..22a4c6a36 100644 --- a/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java +++ b/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java @@ -21,6 +21,31 @@ public AuthInterceptor(JwtUtil jwtUtil) { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + isGetMethod(request); + if (isPostMethod(request) || isPatchMethod(request) || isDeleteMethod(request)) { + checkAccessToken(request); + } + + return true; + } + + private boolean isGetMethod(HttpServletRequest request) { + return request.getMethod().equals("GET"); + } + + private boolean isPostMethod(HttpServletRequest request) { + return request.getMethod().equals("POST"); + } + + private boolean isPatchMethod(HttpServletRequest request) { + return request.getMethod().equals("PATCH"); + } + + private boolean isDeleteMethod(HttpServletRequest request) { + return request.getMethod().equals("DELETE"); + } + + private boolean checkAccessToken(HttpServletRequest request) { String authorization = request.getHeader("Authorization"); if (authorization == null) throw new AccessTokenNotFoundException(); String accessToken = authorization.substring("Bearer ".length()); @@ -31,4 +56,5 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons } return true; } + } From b65d5601acf9a5279cad10a0844588b6bb26fc52 Mon Sep 17 00:00:00 2001 From: tmxhsk99 Date: Sat, 12 Aug 2023 20:10:19 +0900 Subject: [PATCH 29/36] =?UTF-8?q?chore=20:=20=EB=AA=85=ED=99=95=ED=95=98?= =?UTF-8?q?=EA=B2=8C=20=EB=B0=9C=EC=83=9D=20Exception=20=ED=83=80=EC=9E=85?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/codesoom/assignment/interceptor/AuthInterceptor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java b/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java index 22a4c6a36..5c3a0405b 100644 --- a/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java +++ b/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java @@ -45,7 +45,7 @@ private boolean isDeleteMethod(HttpServletRequest request) { return request.getMethod().equals("DELETE"); } - private boolean checkAccessToken(HttpServletRequest request) { + private boolean checkAccessToken(HttpServletRequest request) throws InvalidAccessTokenException, AccessTokenNotFoundException { String authorization = request.getHeader("Authorization"); if (authorization == null) throw new AccessTokenNotFoundException(); String accessToken = authorization.substring("Bearer ".length()); From a1cf15c75e2c1a31a45344f6c0f5afcec6166d04 Mon Sep 17 00:00:00 2001 From: tmxhsk99 Date: Sat, 12 Aug 2023 20:13:16 +0900 Subject: [PATCH 30/36] =?UTF-8?q?fix=20:=20interceptor=20Path=20=ED=8C=A8?= =?UTF-8?q?=ED=84=B4=20=EC=88=98=EC=A0=95,=20=EB=88=84=EB=9D=BD=EB=90=9C?= =?UTF-8?q?=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=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 누락된 @Configuration 어노테이션 추가 기존의 path 패턴의 경우 해당 인증 확인 로직을 타지 않는 경우가 있기 때문에 수정 --- .../main/java/com/codesoom/assignment/config/WebConfig.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/codesoom/assignment/config/WebConfig.java b/app/src/main/java/com/codesoom/assignment/config/WebConfig.java index 92d78eb52..bc467b7fb 100644 --- a/app/src/main/java/com/codesoom/assignment/config/WebConfig.java +++ b/app/src/main/java/com/codesoom/assignment/config/WebConfig.java @@ -1,9 +1,11 @@ package com.codesoom.assignment.config; import com.codesoom.assignment.interceptor.AuthInterceptor; +import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +@Configuration public class WebConfig implements WebMvcConfigurer { private final AuthInterceptor authInterceptor; @@ -14,7 +16,7 @@ public WebConfig(AuthInterceptor authInterceptor) { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authInterceptor) - .addPathPatterns("/products"); + .addPathPatterns("/products/**"); } } From fa862e87440b93150702e66396490c0f1f0addd8 Mon Sep 17 00:00:00 2001 From: tmxhsk99 Date: Sat, 12 Aug 2023 20:15:05 +0900 Subject: [PATCH 31/36] =?UTF-8?q?test=20:=20ProductControllerTest=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EC=9D=B8?= =?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 계층형 테스트 구조로 수정 하고, 인터셉터 추가에 따른 인증로직 검증 테스트 추가 --- .../controllers/ProductControllerTest.java | 466 +++++++++++++----- 1 file changed, 329 insertions(+), 137 deletions(-) diff --git a/app/src/test/java/com/codesoom/assignment/controllers/ProductControllerTest.java b/app/src/test/java/com/codesoom/assignment/controllers/ProductControllerTest.java index a387bea09..a032c1ed2 100644 --- a/app/src/test/java/com/codesoom/assignment/controllers/ProductControllerTest.java +++ b/app/src/test/java/com/codesoom/assignment/controllers/ProductControllerTest.java @@ -3,9 +3,15 @@ import com.codesoom.assignment.application.ProductService; import com.codesoom.assignment.domain.Product; import com.codesoom.assignment.dto.ProductData; +import com.codesoom.assignment.errors.InvalidAccessTokenException; import com.codesoom.assignment.errors.ProductNotFoundException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import com.codesoom.assignment.utils.JwtUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.jsonwebtoken.Claims; +import org.junit.jupiter.api.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -14,175 +20,361 @@ import java.util.List; +import static com.codesoom.assignment.utils.TestHelper.*; import static org.hamcrest.Matchers.containsString; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.verify; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @WebMvcTest(ProductController.class) +@SuppressWarnings({"InnerClassMayBeStatic", "NonAsciiCharacters"}) +@DisplayName("ProductController 클래스") class ProductControllerTest { - private static final String VALID_TOKEN = "eyJhbGciOiJIUzI1NiJ9." + - "eyJ1c2VySWQiOjF9.ZZ3CUl0jxeLGvQ1Js5nG2Ty5qGTlqai5ubDMXZOdaDk"; - private static final String INVALID_TOKEN = "eyJhbGciOiJIUzI1NiJ9." + - "eyJ1c2VySWQiOjF9.ZZ3CUl0jxeLGvQ1Js5nG2Ty5qGTlqai5ubDMXZOdaD0"; @Autowired private MockMvc mockMvc; + @Autowired + private ObjectMapper objectMapper; + @MockBean private ProductService productService; - @BeforeEach - void setUp() { - Product product = Product.builder() - .id(1L) - .name("쥐돌이") - .maker("냥이월드") - .price(5000) - .build(); - given(productService.getProducts()).willReturn(List.of(product)); - - given(productService.getProduct(1L)).willReturn(product); - - given(productService.getProduct(1000L)) - .willThrow(new ProductNotFoundException(1000L)); - - given(productService.createProduct(any(ProductData.class))) - .willReturn(product); - - given(productService.updateProduct(eq(1L), any(ProductData.class))) - .will(invocation -> { - Long id = invocation.getArgument(0); - ProductData productData = invocation.getArgument(1); - return Product.builder() - .id(id) - .name(productData.getName()) - .maker(productData.getMaker()) - .price(productData.getPrice()) - .build(); - }); + @MockBean + private JwtUtil jwtUtil; - given(productService.updateProduct(eq(1000L), any(ProductData.class))) - .willThrow(new ProductNotFoundException(1000L)); + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class list_메서드는 { - given(productService.deleteProduct(1000L)) - .willThrow(new ProductNotFoundException(1000L)); - } + @BeforeEach + void setUp() { + given(productService.getProducts()).willReturn(List.of(TEST_PRODUCT)); + } - @Test - void list() throws Exception { - mockMvc.perform( - get("/products") - .accept(MediaType.APPLICATION_JSON_UTF8) - ) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("쥐돌이"))); + @Test + @DisplayName("상품목록을 반환한다") + void It_returns_product_list() throws Exception { + mockMvc.perform(get("/products") + .accept(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()) + .andExpect(content().string(containsString(TEST_PRODUCT_NAME))); + } } - @Test - void deatilWithExsitedProduct() throws Exception { - mockMvc.perform( - get("/products/1") - .accept(MediaType.APPLICATION_JSON_UTF8) - ) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("쥐돌이"))); - } + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class detail_메서드는 { - @Test - void deatilWithNotExsitedProduct() throws Exception { - mockMvc.perform(get("/products/1000")) - .andExpect(status().isNotFound()); - } + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 요청받은_id에_해당하는_상품이_존재하는_경우 { + @BeforeEach + void setUp() { + given(productService.getProduct(1L)).willReturn(TEST_PRODUCT); + } - @Test - void createWithValidAttributes() throws Exception { - mockMvc.perform( - post("/products") - .accept(MediaType.APPLICATION_JSON_UTF8) - .contentType(MediaType.APPLICATION_JSON) - .content("{\"name\":\"쥐돌이\",\"maker\":\"냥이월드\"," + - "\"price\":5000}") - ) - .andExpect(status().isCreated()) - .andExpect(content().string(containsString("쥐돌이"))); - - verify(productService).createProduct(any(ProductData.class)); - } + @Test + @DisplayName("해당 id의 상품을 반환한다") + void It_returns_product() throws Exception { + mockMvc.perform(get("/products/1") + .accept(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()) + .andExpect(content().string(containsString(TEST_PRODUCT_NAME))); + } + } - @Test - void createWithInvalidAttributes() throws Exception { - mockMvc.perform( - post("/products") - .accept(MediaType.APPLICATION_JSON_UTF8) - .contentType(MediaType.APPLICATION_JSON) - .content("{\"name\":\"\",\"maker\":\"\"," + - "\"price\":0}") - ) - .andExpect(status().isBadRequest()); - } + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 요청받은_id에_해당하는_상품이_존재하지_않는_경우 { + @BeforeEach + void setUp() { + given(productService.getProduct(1000L)) + .willThrow(new ProductNotFoundException(1000L)); + } - @Test - void updateWithExistedProduct() throws Exception { - mockMvc.perform( - patch("/products/1") - .accept(MediaType.APPLICATION_JSON_UTF8) - .contentType(MediaType.APPLICATION_JSON) - .content("{\"name\":\"쥐순이\",\"maker\":\"냥이월드\"," + - "\"price\":5000}") - ) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("쥐순이"))); - - verify(productService).updateProduct(eq(1L), any(ProductData.class)); - } + @Test + @DisplayName("에러메시지를 반환한다") + void It_returns_404_error() throws Exception { + mockMvc.perform(get("/products/1000") + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(status().isNotFound()) + .andDo(print()); + } + } - @Test - void updateWithNotExistedProduct() throws Exception { - mockMvc.perform( - patch("/products/1000") - .contentType(MediaType.APPLICATION_JSON) - .content("{\"name\":\"쥐순이\",\"maker\":\"냥이월드\"," + - "\"price\":5000}") - ) - .andExpect(status().isNotFound()); - - verify(productService).updateProduct(eq(1000L), any(ProductData.class)); } - @Test - void updateWithInvalidAttributes() throws Exception { - mockMvc.perform( - patch("/products/1") - .accept(MediaType.APPLICATION_JSON_UTF8) - .contentType(MediaType.APPLICATION_JSON) - .content("{\"name\":\"\",\"maker\":\"\"," + - "\"price\":0}") - ) - .andExpect(status().isBadRequest()); + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class create_메서드는 { + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 유효한_토큰을_전달받은_경우 { + @BeforeEach + void setUp() { + given(jwtUtil.decode(VALID_TOKEN)).will(invocation -> { + String accessToken = invocation.getArgument(0); + Claims claims = new JwtUtil("12345678901234567890123456789010").decode(accessToken); + return claims; + }); + } + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 상품_요청이_정상적인_경우 { + @BeforeEach + void setUp() { + given(productService.createProduct(any(ProductData.class))) + .willReturn(TEST_PRODUCT); + } + + @Test + @DisplayName("상품을 생성하고, 생성된 상품을 반환한다") + void It_creates_product_and_returns_it() throws Exception { + mockMvc.perform(post("/products") + .header("Authorization", "Bearer " + VALID_TOKEN) + .accept(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(objectMapper.writeValueAsString(TEST_PRODUCT_DATA))) + .andExpect(status().isCreated()) + .andExpect(content().string(containsString(TEST_PRODUCT_NAME))); + } + } + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 상품요청이_비정상적인_경우 { + + @ParameterizedTest + @MethodSource("com.codesoom.assignment.utils.TestHelper#provideInvalidProductRequests") + @DisplayName("에러메시지를 반환한다") + void It_returns_400_error() throws Exception { + mockMvc.perform(post("/products") + .header("Authorization", "Bearer " + VALID_TOKEN) + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()) + .andDo(print()); + } + } + + } + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 유효하지_않은_토큰을_전달받은_경우 { + @BeforeEach + void setUp() { + Mockito.reset(jwtUtil); + given(jwtUtil.decode(INVALID_TOKEN)).willThrow(new InvalidAccessTokenException()); + } + + @Test + @DisplayName("에러메시지를 반환한다") + void It_returns_401_error() throws Exception { + mockMvc.perform(post("/products") + .header("Authorization", "Bearer " + INVALID_TOKEN) + .accept(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(objectMapper.writeValueAsString(TEST_PRODUCT_DATA))) + .andExpect(status().isUnauthorized()) + .andDo(print()); + } + } } - @Test - void destroyWithExistedProduct() throws Exception { - mockMvc.perform( - delete("/products/1") - ) - .andExpect(status().isNoContent()); + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class update_메서드는 { + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 유효한_토큰을_전달받은_경우 { + @BeforeEach + void setUp() { + given(jwtUtil.decode(VALID_TOKEN)).will(invocation -> { + String accessToken = invocation.getArgument(0); + Claims claims = new JwtUtil("12345678901234567890123456789010").decode(accessToken); + return claims; + }); + } + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 상품_요청이_정상적인_경우 { + @BeforeEach + void setUp() { + given(productService.updateProduct(eq(1L), any(ProductData.class))) + .will(invocation -> { + Long id = invocation.getArgument(0); + ProductData productData = invocation.getArgument(1); + return Product.builder() + .id(id) + .name(productData.getName()) + .maker(productData.getMaker()) + .price(productData.getPrice()) + .build(); + }); + } + + @Test + @DisplayName("상품을 수정하고, 수정된 상품을 반환한다") + void It_updates_product_and_returns_it() throws Exception { + mockMvc.perform(patch("/products/1") + .header("Authorization", "Bearer " + VALID_TOKEN) + .accept(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(objectMapper.writeValueAsString(UPDATE_PRODUCT_DATA))) + .andExpect(status().isOk()) + .andExpect(content().string(containsString(TEST_UPDATE_PRODUCT_NAME))); + } + } + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 상품요청이_비정상적인_경우 { + @BeforeEach + void setUp() { + given(jwtUtil.decode(VALID_TOKEN)).willReturn(null); + } + + @ParameterizedTest + @MethodSource("com.codesoom.assignment.utils.TestHelper#provideInvalidProductRequests") + @DisplayName("에러메시지를 반환한다") + void It_returns_400_error() throws Exception { + mockMvc.perform(patch("/products/1") + .header("Authorization", "Bearer " + VALID_TOKEN) + .accept(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()) + .andDo(print()); + } + } + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 수정할_상품_정보가_없는경우 { + @BeforeEach + void setUp() { + given(productService.updateProduct(eq(1000L), any(ProductData.class))) + .willThrow(new ProductNotFoundException(1000L)); + } + + @Test + @DisplayName("에러메시지를 반환한다") + void It_returns_404_error() throws Exception { + mockMvc.perform(patch("/products/1000") + .header("Authorization", "Bearer " + VALID_TOKEN) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(objectMapper.writeValueAsString(UPDATE_PRODUCT_DATA))) + .andExpect(status().isNotFound()) + .andDo(print()); + } + } - verify(productService).deleteProduct(1L); + } + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 유효하지_않은_토큰을_전달받은_경우 { + @BeforeEach + void setUp() { + Mockito.reset(jwtUtil); + given(jwtUtil.decode(INVALID_TOKEN)).willThrow(new InvalidAccessTokenException()); + } + + @Test + @DisplayName("에러메시지를 반환한다") + void It_returns_401_error() throws Exception { + mockMvc.perform(patch("/products/1") + .header("Authorization", "Bearer " + INVALID_TOKEN) + .accept(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(objectMapper.writeValueAsString(UPDATE_PRODUCT_DATA))) + .andExpect(status().isUnauthorized()) + .andDo(print()); + } + } } - @Test - void destroyWithNotExistedProduct() throws Exception { - mockMvc.perform( - delete("/products/1000") - ) - .andExpect(status().isNotFound()); + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class destroy_메서드는 { + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 유효한_토큰을_전달받은_경우 { + @BeforeEach + void setUp() { + given(jwtUtil.decode(VALID_TOKEN)).will(invocation -> { + String accessToken = invocation.getArgument(0); + Claims claims = new JwtUtil("12345678901234567890123456789010").decode(accessToken); + return claims; + }); + } + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 상품_삭제요청이_정상적인_경우 { + @Test + @DisplayName("상품을 삭제한다") + void It_delete_product() throws Exception { + mockMvc.perform(delete("/products/1") + .header("Authorization", "Bearer " + VALID_TOKEN) + .accept(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(objectMapper.writeValueAsString(UPDATE_PRODUCT_DATA))) + .andExpect(status().isNoContent()); + } + } + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 삭제할_상품_정보가_없는경우 { + @BeforeEach + void setUp() { + given(productService.deleteProduct(1000L)) + .willThrow(new ProductNotFoundException(1000L)); + } + + @Test + @DisplayName("에러메시지를 반환한다") + void It_returns_404_error() throws Exception { + mockMvc.perform(delete("/products/1000") + .header("Authorization", "Bearer " + VALID_TOKEN) + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(status().isNotFound()) + .andDo(print()); + } + } + + } + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 유효하지_않은_토큰을_전달받은_경우 { + @BeforeEach + void setUp() { + Mockito.reset(jwtUtil); + given(jwtUtil.decode(INVALID_TOKEN)).willThrow(new InvalidAccessTokenException()); + } - verify(productService).deleteProduct(1000L); + @Test + @DisplayName("에러메시지를 반환한다") + void It_returns_401_error() throws Exception { + mockMvc.perform(delete("/products/1") + .header("Authorization", "Bearer " + INVALID_TOKEN) + .accept(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(status().isUnauthorized()) + .andDo(print()); + } + } } } From 8f2991d6208d9929de6feb6c053d6c61ebd458fa Mon Sep 17 00:00:00 2001 From: tmxhsk99 Date: Sat, 12 Aug 2023 20:37:04 +0900 Subject: [PATCH 32/36] =?UTF-8?q?fix=20:=20=EB=88=84=EB=9D=BD=EB=90=9C=20@?= =?UTF-8?q?CrossOrigin=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=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/codesoom/assignment/controllers/SessionController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/codesoom/assignment/controllers/SessionController.java b/app/src/main/java/com/codesoom/assignment/controllers/SessionController.java index ab067b541..fc7b908d4 100644 --- a/app/src/main/java/com/codesoom/assignment/controllers/SessionController.java +++ b/app/src/main/java/com/codesoom/assignment/controllers/SessionController.java @@ -10,6 +10,7 @@ @RestController @RequestMapping("/session") +@CrossOrigin public class SessionController { private final AuthenticationService authenticationService; From af8d6d616fea733e74789ad67fcd3558f18689d1 Mon Sep 17 00:00:00 2001 From: tmxhsk99 Date: Sat, 12 Aug 2023 20:37:04 +0900 Subject: [PATCH 33/36] =?UTF-8?q?fix=20:=20=EB=88=84=EB=9D=BD=EB=90=9C=20`?= =?UTF-8?q?`@CrossOrigin`=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/codesoom/assignment/controllers/SessionController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/codesoom/assignment/controllers/SessionController.java b/app/src/main/java/com/codesoom/assignment/controllers/SessionController.java index ab067b541..fc7b908d4 100644 --- a/app/src/main/java/com/codesoom/assignment/controllers/SessionController.java +++ b/app/src/main/java/com/codesoom/assignment/controllers/SessionController.java @@ -10,6 +10,7 @@ @RestController @RequestMapping("/session") +@CrossOrigin public class SessionController { private final AuthenticationService authenticationService; From d2350bee27b8afbadca6ea8aa2d24291391df9de Mon Sep 17 00:00:00 2001 From: tmxhsk99 Date: Sun, 13 Aug 2023 08:22:39 +0900 Subject: [PATCH 34/36] =?UTF-8?q?test=20:=20=EC=9C=A0=ED=9A=A8=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=9D=80=20=EC=9C=A0=EC=A0=80=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EC=9A=94=EC=B2=AD=EC=9D=B8=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=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 유효하지 않은 유저로그인 요청인 경우의 테스트가 없었기 때문에 해당 테스트 추가 및 테스트 케이스에 따른 픽스쳐를 TestHelper 클래스에 추가 및 이동시켰습니다. --- .../controllers/SessionControllerTest.java | 36 ++++++++++--- .../codesoom/assignment/utils/TestHelper.java | 51 +++++++++++++++++++ 2 files changed, 80 insertions(+), 7 deletions(-) diff --git a/app/src/test/java/com/codesoom/assignment/controllers/SessionControllerTest.java b/app/src/test/java/com/codesoom/assignment/controllers/SessionControllerTest.java index 16ae53100..fc7f80434 100644 --- a/app/src/test/java/com/codesoom/assignment/controllers/SessionControllerTest.java +++ b/app/src/test/java/com/codesoom/assignment/controllers/SessionControllerTest.java @@ -2,15 +2,19 @@ import com.codesoom.assignment.application.AuthenticationService; import com.codesoom.assignment.dto.UserLoginData; +import com.codesoom.assignment.utils.JwtUtil; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import static com.codesoom.assignment.utils.TestHelper.*; +import static com.codesoom.assignment.utils.TestHelper.AUTH_USER_LOGIN_DATA; +import static com.codesoom.assignment.utils.TestHelper.VALID_TOKEN; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -28,11 +32,9 @@ class SessionControllerTest { ObjectMapper objectMapper; @MockBean AuthenticationService authenticationService; - - private UserLoginData AUTH_USER_DATA = UserLoginData.builder() - .email(AUTH_EMAIL) - .password(AUTH_PASSWORD) - .build(); + @MockBean + JwtUtil jwtUtil; + @Nested @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @@ -51,7 +53,7 @@ class 유효한_유저로그인정보_요청를_받으면 { @DisplayName("인증토큰을 반환한다.") @Test void It_returns_token() throws Exception { - String jsonString = objectMapper.writeValueAsString(AUTH_USER_DATA); + String jsonString = objectMapper.writeValueAsString(AUTH_USER_LOGIN_DATA); mockMvc.perform(post("/session") .contentType(MediaType.APPLICATION_JSON) @@ -60,5 +62,25 @@ void It_returns_token() throws Exception { .andExpect(jsonPath("accessToken").value(VALID_TOKEN)); } } + + @Nested + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) + class 유효하지_않은_유저로그인_요청을_받으면 { + + @DisplayName("예외를 반환한다.") + @ParameterizedTest + @MethodSource("com.codesoom.assignment.utils.TestHelper#provideInvalidUserLoginRequests") + void It_returns_exception(UserLoginData loginData) throws Exception { + String jsonString = objectMapper.writeValueAsString(loginData); + + mockMvc.perform(post("/session") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(jsonString)) + .andExpect(status().isBadRequest()); + } + + + } } } diff --git a/app/src/test/java/com/codesoom/assignment/utils/TestHelper.java b/app/src/test/java/com/codesoom/assignment/utils/TestHelper.java index ed053bcd5..87a9d8349 100644 --- a/app/src/test/java/com/codesoom/assignment/utils/TestHelper.java +++ b/app/src/test/java/com/codesoom/assignment/utils/TestHelper.java @@ -23,6 +23,13 @@ public class TestHelper { public static final int TEST_PRODUCT_PRICE = 5000; public static final String INVALID_PASSWORD = AUTH_PASSWORD + "INVALID"; public static final MockHttpServletRequest INVALID_SERVLET_REQUEST = new MockHttpServletRequest(); + private static final String TEST_LONG_PASSWORD = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut dignissim ex vitae congue congue. Nunc fermentum tellus leo. Donec malesuada, dolor non euismod suscipit, quam elit scelerisque ligula, in finibus eros justo eu justo. Duis tempor porta odio, id finibus nibh pellentesque congue. Ut et velit eget nibh tincidunt porta et id risus. Vestibulum suscipit ullamcorper varius. Proin eget arcu quam. Cras id feugiat libero. Integer auctor sem nec tempor pellentesque. Donec tempor molestie ex in viverra. Aliquam nec purus consequat purus ullamcorper tristique eu sodales erat. Nunc vitae accumsan orci. Vestibulum dictum ante non hendrerit convallis. Ut eu interdum nisl.\n" + + "\n" + + "Vestibulum et tellus tortor. Maecenas vulputate urna eu massa mattis, eu vulputate magna pretium. Vestibulum at sapien vitae mi tempus elementum at eget ante. Morbi risus dolor, eleifend eu ante sed, commodo aliquam augue. Pellentesque aliquet, tellus ultrices fermentum bibendum, turpis urna mollis mauris, sagittis posuere dolor mi et enim. Quisque mollis vulputate est vel eleifend. Donec nec sollicitudin massa. Sed mattis posuere metus sed dictum. Pellentesque varius est a arcu vulputate sollicitudin.\n" + + "\n" + + "Cras ac diam vehicula, elementum mauris tempus, accumsan lacus. Sed lectus diam, hendrerit a consequat id, eleifend eget libero. Praesent laoreet tempor magna et imperdiet. Aenean dictum non velit id lacinia. Donec congue ante dui, id rutrum ex accumsan at. Nulla ut massa elementum, posuere nunc sit amet, ornare nisl. Pellentesque in dui ipsum. Vivamus placerat velit sit amet tempus efficitur.\n" + + "\n" + + "Donec auctor lacus sit amet neque luctus, vitae tincidunt tortor lobortis. Fusce aliquam sem ut magna sollicitudin, ac vulputate est placerat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam scelerisque augue elit, at bibendum libero efficitur ac. Sed fringilla purus pretium tortor condimentum imperdiet. Praesent in nibh lacinia, euismod enim eu, bibendum felis. Aliquam quis placerat ipsum. Integer dictum volutpat."; public static final UserLoginData IS_NOT_EXISTS_USER_DATA = UserLoginData.builder() .email(INVALID_EMAIL) @@ -83,4 +90,48 @@ public static MockHttpServletRequest getValidTokenServletRequest() { request.addHeader("Authorization", "Bearer " + VALID_TOKEN); return request; } + + public static UserLoginData AUTH_USER_LOGIN_DATA = UserLoginData.builder() + .email(AUTH_EMAIL) + .password(AUTH_PASSWORD) + .build(); + + public static UserLoginData EMAIL_NULL_LOGIN_USER_DATA = UserLoginData.builder() + .password(AUTH_PASSWORD) + .build(); + + public static UserLoginData PASSWORD_NULL_LOGIN_USER_DATA = UserLoginData.builder() + .email(AUTH_EMAIL) + .build(); + + public static UserLoginData EMPTY_LOGIN_USER_DATA = UserLoginData.builder() + .email("") + .password("") + .build(); + + public static UserLoginData EMAIL_IS_SHORT_LOGIN_USER_DATA = UserLoginData.builder() + .email("aa") + .password(AUTH_PASSWORD) + .build(); + + public static UserLoginData PASSWORD_IS_TOO_SHORT_LOGIN_USER_DATA = UserLoginData.builder() + .email(AUTH_EMAIL) + .password("111") + .build(); + + public static UserLoginData PASSWORD_IS_TOO_LONG_LOGIN_USER_DATA = UserLoginData.builder() + .email(AUTH_EMAIL) + .password(TEST_LONG_PASSWORD) + .build(); + + public static Stream provideInvalidUserLoginRequests() { + return Stream.of( + Arguments.of(EMAIL_NULL_LOGIN_USER_DATA), + Arguments.of(PASSWORD_NULL_LOGIN_USER_DATA), + Arguments.of(EMPTY_LOGIN_USER_DATA), + Arguments.of(EMAIL_IS_SHORT_LOGIN_USER_DATA), + Arguments.of(PASSWORD_IS_TOO_SHORT_LOGIN_USER_DATA), + Arguments.of(PASSWORD_IS_TOO_LONG_LOGIN_USER_DATA) + ); + } } From 47aea1de97dbe606bea66680ea4afc6a03ba8fef Mon Sep 17 00:00:00 2001 From: juhyeon Date: Mon, 14 Aug 2023 13:39:18 +0900 Subject: [PATCH 35/36] =?UTF-8?q?fix=20:=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EB=B6=84=EA=B8=B0=EB=AC=B8=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 코드를 작성 누락으로 인한 로직 수정 --- .../codesoom/assignment/interceptor/AuthInterceptor.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java b/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java index 5c3a0405b..7f6e3b684 100644 --- a/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java +++ b/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java @@ -21,9 +21,12 @@ public AuthInterceptor(JwtUtil jwtUtil) { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - isGetMethod(request); + if (isGetMethod(request)) { + return true; + } + if (isPostMethod(request) || isPatchMethod(request) || isDeleteMethod(request)) { - checkAccessToken(request); + return checkAccessToken(request); } return true; From 9f04b7af2b0a1e6d74dca4ea42f9083346f8a568 Mon Sep 17 00:00:00 2001 From: juhyeon Date: Mon, 14 Aug 2023 13:53:52 +0900 Subject: [PATCH 36/36] =?UTF-8?q?refactor=20:=20=EA=B0=80=EB=8F=85?= =?UTF-8?q?=EC=84=B1=EC=9D=84=20=EC=9C=84=ED=95=9C=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../codesoom/assignment/interceptor/AuthInterceptor.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java b/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java index 7f6e3b684..acd166433 100644 --- a/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java +++ b/app/src/main/java/com/codesoom/assignment/interceptor/AuthInterceptor.java @@ -24,7 +24,7 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons if (isGetMethod(request)) { return true; } - + if (isPostMethod(request) || isPatchMethod(request) || isDeleteMethod(request)) { return checkAccessToken(request); } @@ -50,14 +50,16 @@ private boolean isDeleteMethod(HttpServletRequest request) { private boolean checkAccessToken(HttpServletRequest request) throws InvalidAccessTokenException, AccessTokenNotFoundException { String authorization = request.getHeader("Authorization"); - if (authorization == null) throw new AccessTokenNotFoundException(); + if (authorization == null) { + throw new AccessTokenNotFoundException(); + } String accessToken = authorization.substring("Bearer ".length()); try { jwtUtil.decode(accessToken); + return true; } catch (Exception e) { throw new InvalidAccessTokenException(e.getMessage()); } - return true; } }