From e0818f3ce83cafbfbc818f67aa10fb8f29957e5b Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 08:17:36 +0900 Subject: [PATCH 01/18] =?UTF-8?q?test:=20Database=20=EA=B4=80=EB=A0=A8=20t?= =?UTF-8?q?est=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/database/DatabaseCleanup.java | 52 +++++++++++++++++++ .../support/database/DatabaseTest.java | 17 ++++++ 2 files changed, 69 insertions(+) create mode 100644 backend/core/src/test/java/com/rollthedice/backend/support/database/DatabaseCleanup.java create mode 100644 backend/core/src/test/java/com/rollthedice/backend/support/database/DatabaseTest.java diff --git a/backend/core/src/test/java/com/rollthedice/backend/support/database/DatabaseCleanup.java b/backend/core/src/test/java/com/rollthedice/backend/support/database/DatabaseCleanup.java new file mode 100644 index 00000000..b4f11264 --- /dev/null +++ b/backend/core/src/test/java/com/rollthedice/backend/support/database/DatabaseCleanup.java @@ -0,0 +1,52 @@ +package com.rollthedice.backend.support.database; + +import jakarta.persistence.Entity; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.Table; +import jakarta.persistence.metamodel.EntityType; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@Profile("test") +public class DatabaseCleanup implements InitializingBean { + + @PersistenceContext + private EntityManager entityManager; + + private List tables; + + @Override + public void afterPropertiesSet() { + tables = entityManager.getMetamodel() + .getEntities() + .stream() + .filter(e -> e.getJavaType().getAnnotation(Entity.class) != null) + .map(this::getTableNameOrElseGetEntityName) + .toList(); + } + + private String getTableNameOrElseGetEntityName(EntityType e) { + Table table = e.getJavaType().getAnnotation(Table.class); + if (table != null && !table.name().isEmpty()) { + return table.name(); + } else { + return e.getName().toLowerCase(); + } + } + + @Transactional + public void execute() { + entityManager.flush(); + entityManager.createNativeQuery("SET FOREIGN_KEY_CHECKS = 0").executeUpdate(); + for (String table : tables) { + entityManager.createNativeQuery("TRUNCATE TABLE " + table).executeUpdate(); + } + entityManager.createNativeQuery("SET FOREIGN_KEY_CHECKS = 1").executeUpdate(); + } +} diff --git a/backend/core/src/test/java/com/rollthedice/backend/support/database/DatabaseTest.java b/backend/core/src/test/java/com/rollthedice/backend/support/database/DatabaseTest.java new file mode 100644 index 00000000..48d45743 --- /dev/null +++ b/backend/core/src/test/java/com/rollthedice/backend/support/database/DatabaseTest.java @@ -0,0 +1,17 @@ +package com.rollthedice.backend.support.database; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Transactional +@ActiveProfiles("test") +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) +public @interface DatabaseTest {} From ce4a3306ba356a14dc5516f927d37b37a3a877fc Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 08:17:50 +0900 Subject: [PATCH 02/18] feat: RepositoryTest --- .../backend/support/RepositoryTest.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 backend/core/src/test/java/com/rollthedice/backend/support/RepositoryTest.java diff --git a/backend/core/src/test/java/com/rollthedice/backend/support/RepositoryTest.java b/backend/core/src/test/java/com/rollthedice/backend/support/RepositoryTest.java new file mode 100644 index 00000000..89b01e50 --- /dev/null +++ b/backend/core/src/test/java/com/rollthedice/backend/support/RepositoryTest.java @@ -0,0 +1,19 @@ +package com.rollthedice.backend.support; + +import com.rollthedice.backend.global.config.JpaAuditingConfig; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@DataJpaTest +@Import({JpaAuditingConfig.class}) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +public @interface RepositoryTest { +} \ No newline at end of file From 1fbdcd41f3353484c55310bc592ea918a2bff888 Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 08:18:42 +0900 Subject: [PATCH 03/18] =?UTF-8?q?test:=20LoginTest=20=EA=B0=84=EC=86=8C?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rollthedice/backend/global/LoginTest.java | 58 ++++--------------- 1 file changed, 11 insertions(+), 47 deletions(-) diff --git a/backend/core/src/test/java/com/rollthedice/backend/global/LoginTest.java b/backend/core/src/test/java/com/rollthedice/backend/global/LoginTest.java index dc64f64d..bc93f257 100644 --- a/backend/core/src/test/java/com/rollthedice/backend/global/LoginTest.java +++ b/backend/core/src/test/java/com/rollthedice/backend/global/LoginTest.java @@ -1,65 +1,29 @@ package com.rollthedice.backend.global; -import com.auth0.jwt.JWT; -import com.auth0.jwt.algorithms.Algorithm; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import com.rollthedice.backend.domain.member.entity.Member; import com.rollthedice.backend.domain.member.repository.MemberRepository; -import com.rollthedice.backend.global.security.jwt.filter.JwtAuthenticationProcessingFilter; -import com.rollthedice.backend.global.security.jwt.refresh.service.RefreshTokenService; -import com.rollthedice.backend.global.security.jwt.service.JwtService; +import com.rollthedice.backend.global.oauth2.service.AuthService; +import com.rollthedice.backend.support.database.DatabaseTest; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.boot.test.mock.mockito.SpyBean; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -import java.util.Date; import static com.rollthedice.backend.domain.member.MemberFixture.MEMBER; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.mockito.Mockito.when; -@WebMvcTest +@DatabaseTest public abstract class LoginTest { - protected MockMvc mockMvc; - @Value("${jwt.secret-key}") - protected String secretKey; - protected String accessToken; - @SpyBean - protected JwtService jwtService; - @MockBean - protected RefreshTokenService refreshTokenService; @MockBean - protected MemberRepository memberRepository; - protected Member loginMember; - @Autowired - private ObjectMapper objectMapper; + protected AuthService authService; - protected String toRequestBody(Object value) throws JsonProcessingException { - return objectMapper.writeValueAsString(value); - } + @Autowired + protected MemberRepository memberRepository; + protected Member loginUser; @BeforeEach - public void loginSetup(WebApplicationContext ctx) { - mockMvc = MockMvcBuilders - .webAppContextSetup(ctx) - .addFilter(new JwtAuthenticationProcessingFilter(jwtService, memberRepository, refreshTokenService)) - .alwaysDo(print()) - .build(); - - loginMember = MEMBER(); - - Date now = new Date(); - accessToken = JWT.create() - .withSubject("AccessToken") - .withExpiresAt(new Date(now.getTime() + 18000)) - .withClaim("email", loginMember.getEmail()) - .sign(Algorithm.HMAC512(secretKey)); + public void setup() { + loginUser = memberRepository.save(MEMBER()); + when(authService.getMember()).thenReturn(loginUser); } } From 5145f6c08db24f865a701a9adfb5b21fde570782 Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 08:19:13 +0900 Subject: [PATCH 04/18] =?UTF-8?q?chore:=20restAssured=20=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/core/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/core/build.gradle b/backend/core/build.gradle index 4f334773..8c0c2e44 100644 --- a/backend/core/build.gradle +++ b/backend/core/build.gradle @@ -51,6 +51,7 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' + testImplementation 'io.rest-assured:rest-assured:5.1.1' } tasks.named('bootBuildImage') { From 34f5da98d88be935a5fa9e77129362a02944c1f6 Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 08:19:48 +0900 Subject: [PATCH 05/18] =?UTF-8?q?remove:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=9D=98=EC=A1=B4=EC=84=B1=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/rollthedice/backend/domain/news/api/NewsController.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/news/api/NewsController.java b/backend/core/src/main/java/com/rollthedice/backend/domain/news/api/NewsController.java index a6e38e45..0f50123a 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/news/api/NewsController.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/news/api/NewsController.java @@ -1,6 +1,5 @@ package com.rollthedice.backend.domain.news.api; -import com.rollthedice.backend.domain.crawling.NewsCrawlingService; import com.rollthedice.backend.domain.news.dto.response.NewsDetailResponse; import com.rollthedice.backend.domain.news.dto.response.NewsResponse; import com.rollthedice.backend.domain.news.dto.response.ReadNewsResponse; @@ -19,7 +18,6 @@ public class NewsController implements NewsApi { private final NewsService newsService; private final ReadNewsService readNewsService; - private final NewsCrawlingService crawlingService; @ResponseStatus(HttpStatus.OK) @GetMapping("") From e199d287ced1f0760b1400cc4ded6538ed279fbf Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 08:21:46 +0900 Subject: [PATCH 06/18] =?UTF-8?q?feat:=20News=20Builder=20=ED=95=AD?= =?UTF-8?q?=EB=AA=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rollthedice/backend/domain/news/entity/News.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/news/entity/News.java b/backend/core/src/main/java/com/rollthedice/backend/domain/news/entity/News.java index 5a69e036..c96859cd 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/news/entity/News.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/news/entity/News.java @@ -2,10 +2,7 @@ import com.rollthedice.backend.global.config.BaseTimeEntity; import jakarta.persistence.*; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.*; import lombok.extern.slf4j.Slf4j; import org.hibernate.annotations.ColumnDefault; @@ -31,9 +28,14 @@ public class News extends BaseTimeEntity { private long views; @Builder - public News(String url, String thumbnailUrl) { + public News(Long id, String url, String thumbnailUrl, String title, String content, String category, String postDate) { + this.id = id; this.url = url; this.thumbnailUrl = thumbnailUrl; + this.title = title; + this.content = content; + this.category = category; + this.postDate = postDate; } public void addNewsBody(String title, String content, String category, String postDate) { From 80e3bc1a7dd25be86fab03b5460cc67c7658130e Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 08:22:25 +0900 Subject: [PATCH 07/18] =?UTF-8?q?remove:=20AuthTest=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/auth/AuthTest.java | 109 ------------------ 1 file changed, 109 deletions(-) delete mode 100644 backend/core/src/test/java/com/rollthedice/backend/domain/auth/AuthTest.java diff --git a/backend/core/src/test/java/com/rollthedice/backend/domain/auth/AuthTest.java b/backend/core/src/test/java/com/rollthedice/backend/domain/auth/AuthTest.java deleted file mode 100644 index 9d1f0085..00000000 --- a/backend/core/src/test/java/com/rollthedice/backend/domain/auth/AuthTest.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.rollthedice.backend.domain.auth; - -import com.auth0.jwt.JWT; -import com.auth0.jwt.algorithms.Algorithm; -import com.rollthedice.backend.domain.member.api.MemberController; -import com.rollthedice.backend.domain.member.dto.MemberUpdateDto; -import com.rollthedice.backend.domain.member.service.MemberService; -import com.rollthedice.backend.global.LoginTest; -import com.rollthedice.backend.global.security.jwt.refresh.domain.RefreshToken; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -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.ResultActions; - -import java.util.Date; - -import static com.rollthedice.backend.domain.member.MemberFixture.MEMBER; -import static org.mockito.BDDMockito.given; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@DisplayName("JWT 인증테스트의 ") -@WebMvcTest(MemberController.class) -public class AuthTest extends LoginTest { - - @MockBean - private MemberService memberService; - - @Test - @DisplayName("Access Token을 이용한 정상 로그인") - public void accessToken_로그인_성공() throws Exception { - // when - final ResultActions perform = mockMvc.perform(post("/members").contentType(MediaType.APPLICATION_JSON) - .content(toRequestBody(new MemberUpdateDto("yeonjy"))) - .header("Authorization", "Bearer " + accessToken)); - - // then - perform.andExpect(status().isOk()); - } - - @Test - @DisplayName("Access Token 기간 만료로 인한 멤버 업데이트 실패") - public void access_token_기간만료() throws Exception { - // given -> 시간이 만료된 accessToken 생성 - Date now = new Date(); - String accessToken = JWT.create() - .withSubject("AccessToken") - .withExpiresAt(new Date(now.getTime() - 1000)) - .withClaim("email", MEMBER().getEmail()) - .sign(Algorithm.HMAC512(secretKey)); - - // when - final ResultActions perform = mockMvc.perform(post("/members").contentType(MediaType.APPLICATION_JSON) - .content(toRequestBody(new MemberUpdateDto("yeonjy"))) - .header("Authorization", "Bearer " + accessToken)); - - // then - perform.andExpect(status().isForbidden()); - } - - @Test - @DisplayName("Refresh Token 전송으로 인한 access_token refresh_token 재발급") - public void refreshToken과_accessToken_재발급() throws Exception { - // given -> refresh Token 세팅 및 redis 에서 refresh Token이 있는지 조회 - Date now = new Date(); - String refreshToken = JWT.create() - .withSubject("RefreshToken") - .withExpiresAt(new Date(now.getTime() + 18000)) - .sign(Algorithm.HMAC512(secretKey)); - - RefreshToken token = new RefreshToken(MEMBER().getEmail()); - - given(refreshTokenService.findByToken(refreshToken)).willReturn(token); - - // when - final ResultActions perform = mockMvc.perform(post("/members").contentType(MediaType.APPLICATION_JSON) - .content(toRequestBody(new MemberUpdateDto("yeonjy"))) - .header("Authorization-refresh", "Bearer " + refreshToken)).andDo(print()); - - // then - perform.andExpect(status().isForbidden()) - .andExpect(header().exists("Authorization")) - .andExpect(header().exists("Authorization-refresh")); - } - - @Test - @DisplayName("Refresh Token 만료") - public void refreshToken_만료() throws Exception { - // given -> 만료된 refreshToken 설정 - Date now = new Date(); - String refreshToken = JWT.create() - .withSubject("RefreshToken") - .withExpiresAt(new Date(now.getTime() - 1000)) - .sign(Algorithm.HMAC512(secretKey)); - - // when - final ResultActions perform = mockMvc.perform(post("/members").contentType(MediaType.APPLICATION_JSON) - .content(toRequestBody(new MemberUpdateDto("yeonjy"))) - .header("Authorization-refresh", "Bearer " + refreshToken)).andDo(print()); - - // then - perform.andExpect(status().isForbidden()); - } -} - From 6131814970a1d929a1d075fdc5a7ce38ba5353dc Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 08:23:03 +0900 Subject: [PATCH 08/18] rename: message -> errorMessage --- .../rollthedice/backend/global/error/ErrorCode.java | 2 +- .../backend/global/error/ErrorResponse.java | 12 +++++------- .../backend/global/error/GlobalExceptionHandler.java | 2 +- .../global/error/exception/BusinessException.java | 2 +- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/backend/core/src/main/java/com/rollthedice/backend/global/error/ErrorCode.java b/backend/core/src/main/java/com/rollthedice/backend/global/error/ErrorCode.java index 93923466..9b1e03ce 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/global/error/ErrorCode.java +++ b/backend/core/src/main/java/com/rollthedice/backend/global/error/ErrorCode.java @@ -21,5 +21,5 @@ public enum ErrorCode { private final HttpStatus status; - private final String message; + private final String errorMessage; } diff --git a/backend/core/src/main/java/com/rollthedice/backend/global/error/ErrorResponse.java b/backend/core/src/main/java/com/rollthedice/backend/global/error/ErrorResponse.java index 4d1cecbc..77abd69a 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/global/error/ErrorResponse.java +++ b/backend/core/src/main/java/com/rollthedice/backend/global/error/ErrorResponse.java @@ -3,22 +3,20 @@ import lombok.Getter; import org.springframework.http.HttpStatus; -import java.util.Collections; - @Getter public class ErrorResponse { - private HttpStatus status; - private String message; + private final HttpStatus status; + private final String errorMessage; - public ErrorResponse(HttpStatus status, String message) { + public ErrorResponse(HttpStatus status, String errorMessage) { this.status = status; - this.message = message; + this.errorMessage = errorMessage; } public static ErrorResponse create(final ErrorCode errorCode) { return new ErrorResponse( errorCode.getStatus(), - errorCode.getMessage() + errorCode.getErrorMessage() ); } } \ No newline at end of file diff --git a/backend/core/src/main/java/com/rollthedice/backend/global/error/GlobalExceptionHandler.java b/backend/core/src/main/java/com/rollthedice/backend/global/error/GlobalExceptionHandler.java index 2f734a2f..9b2f6287 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/global/error/GlobalExceptionHandler.java +++ b/backend/core/src/main/java/com/rollthedice/backend/global/error/GlobalExceptionHandler.java @@ -18,7 +18,7 @@ protected ResponseEntity handleRuntimeException(BusinessException return ResponseEntity .status(errorCode.getStatus()) .body(new ErrorResponse(errorCode.getStatus(), - errorCode.getMessage())); + errorCode.getErrorMessage())); } } \ No newline at end of file diff --git a/backend/core/src/main/java/com/rollthedice/backend/global/error/exception/BusinessException.java b/backend/core/src/main/java/com/rollthedice/backend/global/error/exception/BusinessException.java index f3df23c1..05d58347 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/global/error/exception/BusinessException.java +++ b/backend/core/src/main/java/com/rollthedice/backend/global/error/exception/BusinessException.java @@ -8,7 +8,7 @@ public class BusinessException extends RuntimeException{ private final ErrorCode errorCode; public BusinessException(ErrorCode errorCode) { - super(errorCode.getMessage()); + super(errorCode.getErrorMessage()); this.errorCode = errorCode; } } From 2d4c2fd09f82ef14048c8a93f3b6430a0f45ab83 Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 08:24:03 +0900 Subject: [PATCH 09/18] =?UTF-8?q?test:=20Base=20Test=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/global/BaseApiTest.java | 47 +++++++++++++++++ .../backend/global/BaseControllerTest.java | 52 +++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 backend/core/src/test/java/com/rollthedice/backend/global/BaseApiTest.java create mode 100644 backend/core/src/test/java/com/rollthedice/backend/global/BaseControllerTest.java diff --git a/backend/core/src/test/java/com/rollthedice/backend/global/BaseApiTest.java b/backend/core/src/test/java/com/rollthedice/backend/global/BaseApiTest.java new file mode 100644 index 00000000..7f52035c --- /dev/null +++ b/backend/core/src/test/java/com/rollthedice/backend/global/BaseApiTest.java @@ -0,0 +1,47 @@ +package com.rollthedice.backend.global; + +import com.rollthedice.backend.domain.member.entity.Member; +import com.rollthedice.backend.domain.member.repository.MemberRepository; +import com.rollthedice.backend.global.security.jwt.service.JwtService; +import com.rollthedice.backend.support.database.DatabaseCleanup; +import io.restassured.RestAssured; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.test.context.ActiveProfiles; + +import static com.rollthedice.backend.domain.member.MemberFixture.MEMBER; + +@ActiveProfiles("test") +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class BaseApiTest { + @Autowired + private DatabaseCleanup databaseCleanup; + @Autowired + protected MemberRepository memberRepository; + @Autowired + private JwtService jwtService; + + @LocalServerPort + int port; + + protected Member member; + protected String accessToken; + + @BeforeEach + public void setup() { + if (RestAssured.port == RestAssured.UNDEFINED_PORT) { + RestAssured.port = port; + databaseCleanup.afterPropertiesSet(); + } + member = memberRepository.save(MEMBER()); + accessToken = jwtService.createAccessToken(member.getEmail()); + } + + @AfterEach + public void afterEach() { + databaseCleanup.execute(); + } +} diff --git a/backend/core/src/test/java/com/rollthedice/backend/global/BaseControllerTest.java b/backend/core/src/test/java/com/rollthedice/backend/global/BaseControllerTest.java new file mode 100644 index 00000000..b8565cb0 --- /dev/null +++ b/backend/core/src/test/java/com/rollthedice/backend/global/BaseControllerTest.java @@ -0,0 +1,52 @@ +package com.rollthedice.backend.global; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.rollthedice.backend.domain.member.entity.Member; +import com.rollthedice.backend.domain.member.repository.MemberRepository; +import com.rollthedice.backend.global.security.jwt.filter.JwtAuthenticationProcessingFilter; +import com.rollthedice.backend.global.security.jwt.refresh.service.RefreshTokenService; +import com.rollthedice.backend.global.security.jwt.service.JwtService; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import static com.rollthedice.backend.domain.member.MemberFixture.MEMBER; + +@WebMvcTest +public abstract class BaseControllerTest { + protected final String MESSAGE = "$.message"; + protected final String ERROR_MESSAGE = "$.errorMessage"; + + protected MockMvc mockMvc; + protected String accessToken; + protected Member loginMember; + + @SpyBean + protected JwtService jwtService; + @MockBean + protected MemberRepository memberRepository; + @SpyBean + protected ObjectMapper objectMapper; + @MockBean + protected RefreshTokenService refreshTokenService; + + protected String toRequestBody(Object value) throws JsonProcessingException { + return objectMapper.writeValueAsString(value); + } + + @BeforeEach + public void loginSetup(WebApplicationContext ctx) { + mockMvc = MockMvcBuilders.webAppContextSetup(ctx) + .addFilter(new JwtAuthenticationProcessingFilter(jwtService, memberRepository, refreshTokenService)) + .alwaysDo(MockMvcResultHandlers.print()) + .build(); + loginMember = MEMBER(); + accessToken = jwtService.createAccessToken(loginMember.getEmail()); + } +} From 5a170b88fcc52db956d71dcd7ef4402a3fb1e716 Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 08:24:51 +0900 Subject: [PATCH 10/18] refactor: createAccessToken private -> public --- .../backend/global/security/jwt/service/JwtService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/core/src/main/java/com/rollthedice/backend/global/security/jwt/service/JwtService.java b/backend/core/src/main/java/com/rollthedice/backend/global/security/jwt/service/JwtService.java index 73c89ee0..ed9abc12 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/global/security/jwt/service/JwtService.java +++ b/backend/core/src/main/java/com/rollthedice/backend/global/security/jwt/service/JwtService.java @@ -51,7 +51,7 @@ public void sendAccessAndRefreshToken(HttpServletResponse response, String email log.info("Access Token, Refresh Token 헤더 설정 완료"); } - private String createAccessToken(String email) { + public String createAccessToken(String email) { Date now = new Date(); return JWT.create() .withSubject(ACCESS_TOKEN_SUBJECT) From 279990b776826e8beed3ed6560f838c20971b55e Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 08:25:49 +0900 Subject: [PATCH 11/18] =?UTF-8?q?test:=20NewsControllerTest=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/news/NewsFixture.java | 55 +++++++++++ .../news/controller/NewsControllerTest.java | 94 +++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 backend/core/src/test/java/com/rollthedice/backend/domain/news/NewsFixture.java create mode 100644 backend/core/src/test/java/com/rollthedice/backend/domain/news/controller/NewsControllerTest.java diff --git a/backend/core/src/test/java/com/rollthedice/backend/domain/news/NewsFixture.java b/backend/core/src/test/java/com/rollthedice/backend/domain/news/NewsFixture.java new file mode 100644 index 00000000..d9071317 --- /dev/null +++ b/backend/core/src/test/java/com/rollthedice/backend/domain/news/NewsFixture.java @@ -0,0 +1,55 @@ +package com.rollthedice.backend.domain.news; + +import com.rollthedice.backend.domain.member.entity.Member; +import com.rollthedice.backend.domain.news.dto.ContentMessageDto; +import com.rollthedice.backend.domain.news.dto.response.NewsDetailResponse; +import com.rollthedice.backend.domain.news.entity.News; + +public class NewsFixture { + public static News NEWS(Member member) { + return News.builder() + .id(1L) + .url("https://n.news.naver.com/article/025/0003367131?sid=104&type=journalists&cds=news_edit") + .thumbnailUrl("https://imgnews.pstatic.net/image/025/2024/06/17/0003367131_001_20240617001153411.jpg?type=w647") + .title("백지에 펜 1자루, 물 1병만 허용…바이든·트럼프 90분 맨몸 토론") + .content("조 바이든 미국 대통령과 도널드 트럼프 전 대통령이 27일 첫 TV 토론에서 맞붙는다. 2020년 10월 이후 처음으로 성사된 두 사람의 공개 토론이다.\n" + + "\n" + + "CNN이 공개한 세부규칙에 따르면 전·현직 대통령의 첫 TV토론은 청중이 없는 스튜디오에서 진행자만을 가운데 두고 단상에 마주 서는 구조로 진행된다. 누가 어느 쪽 단상을 사용할지는 동전 던지기로 결정한다.\n" + + "\n" + + "생방송 토론에서 두 사람에게 지급되는 건 백지와 펜 한 자루, 물 한병이 전부다. 또 90분 토론 내내 서 있어야 한다. 각각 81세와 78세인 바이든·트럼프 두 후보의 입장에서 보면, 이번 토론은 기억력 대결인 동시에 체력전이 될 전망이다.\n" + + "\n" + + "질문에 대한 답변 시간은 2분. 이후 1분간의 반박 시간이 추가된다. 반박에 대한 재반박 시간 역시 1분이다. 시간 제한이 끝나면 마이크가 꺼진다.\n" + + "\n" + + "토론회의 설계와 감독은 2012년 부통령 후보 토론과 2020년 대선 후보 토론에 이어 이번에도 론 클라인 전 백악관 비서실장이 맡았다. 현지 언론에 따르면 바이든은 철저한 자료분석에 이어 모의 토론을 반복하는 ‘스파링형’으로, 트럼프는 ‘임기응변형’으로 토론 준비를 하고 있다.") + .category("세계") + .postDate("2024.06.17") + .build(); + } + + public static NewsDetailResponse NEWS_DETAIL_RESPONSE() { + return NewsDetailResponse.builder() + .id(1L) + .url("https://n.news.naver.com/article/025/0003367131?sid=104&type=journalists&cds=news_edit") + .thumbnailUrl("https://imgnews.pstatic.net/image/025/2024/06/17/0003367131_001_20240617001153411.jpg?type=w647") + .title("백지에 펜 1자루, 물 1병만 허용…바이든·트럼프 90분 맨몸 토론") + .content("조 바이든 미국 대통령과 도널드 트럼프 전 대통령이 27일 첫 TV 토론에서 맞붙는다. 2020년 10월 이후 처음으로 성사된 두 사람의 공개 토론이다.\n" + + "\n" + + "CNN이 공개한 세부규칙에 따르면 전·현직 대통령의 첫 TV토론은 청중이 없는 스튜디오에서 진행자만을 가운데 두고 단상에 마주 서는 구조로 진행된다. 누가 어느 쪽 단상을 사용할지는 동전 던지기로 결정한다.\n" + + "\n" + + "생방송 토론에서 두 사람에게 지급되는 건 백지와 펜 한 자루, 물 한병이 전부다. 또 90분 토론 내내 서 있어야 한다. 각각 81세와 78세인 바이든·트럼프 두 후보의 입장에서 보면, 이번 토론은 기억력 대결인 동시에 체력전이 될 전망이다.\n" + + "\n" + + "질문에 대한 답변 시간은 2분. 이후 1분간의 반박 시간이 추가된다. 반박에 대한 재반박 시간 역시 1분이다. 시간 제한이 끝나면 마이크가 꺼진다.\n" + + "\n" + + "토론회의 설계와 감독은 2012년 부통령 후보 토론과 2020년 대선 후보 토론에 이어 이번에도 론 클라인 전 백악관 비서실장이 맡았다. 현지 언론에 따르면 바이든은 철저한 자료분석에 이어 모의 토론을 반복하는 ‘스파링형’으로, 트럼프는 ‘임기응변형’으로 토론 준비를 하고 있다.") + .postDate("2024.06.17") + .build(); + } + + public static ContentMessageDto CONTENT_MESSAGE_DTO() { + return new ContentMessageDto(1L, "롯데하이마트가 매장에서 영업을 담당하는 1400여 명의 직원을 직접 고용한다. 대규모유통업법을 준수함과 동시에 직원의 전문성을 제고하기 위한 차원이다."); + } + + + + +} diff --git a/backend/core/src/test/java/com/rollthedice/backend/domain/news/controller/NewsControllerTest.java b/backend/core/src/test/java/com/rollthedice/backend/domain/news/controller/NewsControllerTest.java new file mode 100644 index 00000000..1c790adc --- /dev/null +++ b/backend/core/src/test/java/com/rollthedice/backend/domain/news/controller/NewsControllerTest.java @@ -0,0 +1,94 @@ +package com.rollthedice.backend.domain.news.controller; + +import com.rollthedice.backend.domain.news.api.NewsController; +import com.rollthedice.backend.domain.news.exception.NewsNotFoundException; +import com.rollthedice.backend.domain.news.repository.NewsRepository; +import com.rollthedice.backend.domain.news.service.NewsService; +import com.rollthedice.backend.domain.news.service.ReadNewsService; +import com.rollthedice.backend.global.BaseControllerTest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +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.ResultActions; + +import static com.rollthedice.backend.global.error.ErrorCode.NEWS_NOT_FOUND_ERROR; +import static org.mockito.BDDMockito.given; +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.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + +@DisplayName("NewsController의 ") +@WebMvcTest(NewsController.class) +class NewsControllerTest extends BaseControllerTest { + @MockBean + private NewsService newsService; + @MockBean + private ReadNewsService readNewsService; + @MockBean + private NewsRepository newsRepository; + + @Test + @DisplayName("News 전체 조회 API가 수행되는가") + void getNews() throws Exception { + //when + final ResultActions perform = mockMvc.perform( + get("/news") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer " + accessToken) + ).andDo(print()); + + //then + perform.andExpect(status().isOk()); + } + + @Test + @DisplayName("News 상세 조회 API가 수행되는가") + void getDetailNews() throws Exception { + //when + final ResultActions perform = mockMvc.perform( + get("/news/1") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer " + accessToken) + ).andDo(print()); + + //then + perform.andExpect(status().isOk()); + } + + @Test + @DisplayName("존재하지 않는 News ID를 통한 조회 API를 수행하면 NewsNotFoundException이 반환되는가") + void getDetailNewsNotFound() throws Exception { + //given + Long notExistNewsId = -1L; + given(newsService.getDetailNews(notExistNewsId)).willThrow(new NewsNotFoundException()); + + //when + final ResultActions perform = mockMvc.perform( + get("/news/-1") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer " + accessToken) + ).andDo(print()); + + //then + perform.andExpect(status().isNotFound()) + .andExpect(jsonPath(ERROR_MESSAGE, NEWS_NOT_FOUND_ERROR.getErrorMessage()).exists()); + } + + @Test + @DisplayName("조회한 News 전체 조회 API가 수행되는가") + void getReadNews() throws Exception{ + //when + final ResultActions perform = mockMvc.perform( + get("/news/viewed-history") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer " + accessToken) + ).andDo(print()); + + //then + perform.andExpect(status().isOk()); + } +} From 2d9d3ed3003906adb569d29f6c8e2b91c925ccf1 Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 08:26:02 +0900 Subject: [PATCH 12/18] =?UTF-8?q?test:=20NewsServiceTest=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/news/service/NewsServiceTest.java | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 backend/core/src/test/java/com/rollthedice/backend/domain/news/service/NewsServiceTest.java diff --git a/backend/core/src/test/java/com/rollthedice/backend/domain/news/service/NewsServiceTest.java b/backend/core/src/test/java/com/rollthedice/backend/domain/news/service/NewsServiceTest.java new file mode 100644 index 00000000..df80c961 --- /dev/null +++ b/backend/core/src/test/java/com/rollthedice/backend/domain/news/service/NewsServiceTest.java @@ -0,0 +1,126 @@ +package com.rollthedice.backend.domain.news.service; + +import com.rollthedice.backend.domain.bookmark.repository.BookmarkRepository; +import com.rollthedice.backend.domain.bookmark.service.BookmarkService; +import com.rollthedice.backend.domain.news.dto.ContentMessageDto; +import com.rollthedice.backend.domain.news.dto.response.NewsDetailResponse; +import com.rollthedice.backend.domain.news.dto.response.ReadNewsResponse; +import com.rollthedice.backend.domain.news.entity.News; +import com.rollthedice.backend.domain.news.entity.ReadNews; +import com.rollthedice.backend.domain.news.exception.NewsNotFoundException; +import com.rollthedice.backend.domain.news.mapper.NewsMapper; +import com.rollthedice.backend.domain.news.repository.NewsRepository; +import com.rollthedice.backend.domain.news.repository.ReadNewsRepository; +import com.rollthedice.backend.global.LoginTest; +import com.rollthedice.backend.support.RepositoryTest; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static com.rollthedice.backend.domain.member.MemberFixture.MEMBER; +import static com.rollthedice.backend.domain.news.NewsFixture.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.when; + +@Slf4j +@DisplayName("NewsService의") +@ExtendWith(MockitoExtension.class) +class NewsServiceTest extends LoginTest { + @Autowired + private NewsService newsService; + @MockBean + private BookmarkService bookmarkService; + @MockBean + private NewsRepository newsRepository; + @MockBean + private BookmarkRepository bookmarkRepository; + @MockBean + private ReadNewsRepository readNewsRepository; + @Mock + private NewsMapper newsMapper; + + private News news; + + @BeforeEach + void setUp() { + news = NEWS(MEMBER()); + } + + @Test + @DisplayName("존재하지 않는 News Id로 뉴스를 업데이트하면 NewsNotFoundException이 발생하는가") + void updateSummarizedNews() { + //given + ContentMessageDto dto = CONTENT_MESSAGE_DTO(); + given(newsRepository.findById(dto.getId())).willThrow(NewsNotFoundException.class); + + //when + //then + assertThrows(NewsNotFoundException.class, () -> newsService.updateSummarizedNews(dto)); + } + + @Test + @DisplayName("전체 뉴스가 조회되는가") + void getNews() { + //given + Pageable pageable = PageRequest.of(0, 10); + List newsList = new ArrayList<>(); + int expect = 5; + for (int i = 0; i < expect; i++) { + newsList.add(news); + } + given(newsRepository.findAllByOrderByViewsDescCreatedAtDesc(pageable)).willReturn(newsList); + given(bookmarkService.isBookmarked(loginUser, news)).willReturn(true); + + //when + assertThat(newsService.getNews(pageable)).hasSize(expect); + } + + @Test + @DisplayName("뉴스를 상세조회할 수 있는가") + void getDetailNews() { + //given + NewsDetailResponse expect = NEWS_DETAIL_RESPONSE(); + Long newsId = expect.getId(); + + given(newsRepository.findById(newsId)).willReturn(Optional.of(news)); + + //when + NewsDetailResponse result = newsService.getDetailNews(newsId); + + //then + assertThat(result.getId()).isEqualTo(expect.getId()); + } + + @Test + @DisplayName("읽은 뉴스를 조회할 수 있는가") + void getNewsByReadNews() { + //given + List newsList = new ArrayList<>(); + int expect = 5; + for (int i = 0; i < expect; i++) { + newsList.add(news); + } + + //when + List result = newsService.getNewsByReadNews(newsList); + + //then + assertThat(result).hasSize(expect); + } +} From 208365254ff1f122246a52a9ba8007f9d7888fb9 Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 08:41:40 +0900 Subject: [PATCH 13/18] =?UTF-8?q?test:=20NewsRepository=20Test=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../news/repository/NewsRepositoryTest.java | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 backend/core/src/test/java/com/rollthedice/backend/domain/news/repository/NewsRepositoryTest.java diff --git a/backend/core/src/test/java/com/rollthedice/backend/domain/news/repository/NewsRepositoryTest.java b/backend/core/src/test/java/com/rollthedice/backend/domain/news/repository/NewsRepositoryTest.java new file mode 100644 index 00000000..8b08150a --- /dev/null +++ b/backend/core/src/test/java/com/rollthedice/backend/domain/news/repository/NewsRepositoryTest.java @@ -0,0 +1,77 @@ +package com.rollthedice.backend.domain.news.repository; + +import com.rollthedice.backend.domain.member.entity.Member; +import com.rollthedice.backend.domain.member.repository.MemberRepository; +import com.rollthedice.backend.domain.news.entity.News; +import com.rollthedice.backend.support.RepositoryTest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; + +import java.util.List; + +import static com.rollthedice.backend.domain.member.MemberFixture.MEMBER; +import static com.rollthedice.backend.domain.news.NewsFixture.NEWS; +import static org.assertj.core.api.Assertions.assertThat; + +@DisplayName("NewsRepository의 ") +@RepositoryTest +class NewsRepositoryTest { + @Autowired + private NewsRepository newsRepository; + @Autowired + private MemberRepository memberRepository; + + private Member member; + + @BeforeEach + void setUp() { + member = memberRepository.save(MEMBER()); + } + + @Test + @DisplayName("내용이 없는 기사를 찾을 수 있는가") + void findAllByContentIsNull() { + //given + News news1 = NEWS(member); + News news2 = NEWS(member); + News news3 = News.builder().build(); + newsRepository.save(news1); + newsRepository.save(news2); + newsRepository.save(news3); + + //when + List result = newsRepository.findAllByContentIsNull(); + + //then + assertThat(result).hasSize(1); + } + + @Test + @DisplayName("최신순 및 조회수가 적은 순으로 뉴스 기사를 찾을 수 있는가") + void findAllByOrderByViewsDescCreatedAtDesc() { + //given + Pageable pageable = PageRequest.of(0, 10); + + News news1 = News.builder().build(); + News news2 = News.builder().build(); + News news3 = News.builder().build(); + newsRepository.save(news1); + newsRepository.save(news2); + newsRepository.save(news3); + news1.increaseView(); + news2.increaseView(); + news2.increaseView(); + + //when + List result = newsRepository.findAllByOrderByViewsDescCreatedAtDesc(pageable); + + //then + assertThat(result.indexOf(news2)).isEqualTo(0); + assertThat(result.indexOf(news1)).isEqualTo(1); + assertThat(result.indexOf(news3)).isEqualTo(2); + } +} From 753e4b29472c56adbced26168fbe9848cd203880 Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 08:42:55 +0900 Subject: [PATCH 14/18] =?UTF-8?q?remove:=20Notification=20entity=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notification/entity/Notification.java | 29 ------------------- 1 file changed, 29 deletions(-) delete mode 100644 backend/core/src/main/java/com/rollthedice/backend/domain/notification/entity/Notification.java diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/notification/entity/Notification.java b/backend/core/src/main/java/com/rollthedice/backend/domain/notification/entity/Notification.java deleted file mode 100644 index 6549f239..00000000 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/notification/entity/Notification.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.rollthedice.backend.domain.notification.entity; - -import com.rollthedice.backend.domain.member.entity.Member; -import com.rollthedice.backend.global.config.BaseTimeEntity; -import jakarta.persistence.*; -import lombok.*; - -@Getter -@Entity -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class Notification extends BaseTimeEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - private String content; - private Boolean isLookedUp; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id") - private Member member; - - @Builder - public Notification(String content,Member member) { - this.content = content; - this.member = member; - this.isLookedUp = false; - } -} From 184ed5e588e6b12c7736d9117572b303c668b3f4 Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 08:51:43 +0900 Subject: [PATCH 15/18] =?UTF-8?q?feat:=20test=EC=9A=A9=20application.yml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/test/resources/application-test.yml | 72 +++++++++++++++++++ .../core/src/test/resources/application.yml | 3 + 2 files changed, 75 insertions(+) create mode 100644 backend/core/src/test/resources/application-test.yml create mode 100644 backend/core/src/test/resources/application.yml diff --git a/backend/core/src/test/resources/application-test.yml b/backend/core/src/test/resources/application-test.yml new file mode 100644 index 00000000..7e48f685 --- /dev/null +++ b/backend/core/src/test/resources/application-test.yml @@ -0,0 +1,72 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:tcp://localhost/~/rollthedice + username: sa + password: + jpa: + hibernate: + ddl-auto: create + properties: + hibernate: + format_sql: true + security: + oauth2: + client: + registration: + kakao: + client-id: ${KAKAO_CLIENT_ID} #rest api 키 값 + client-secret: ${KAKAO_CLIENT_SECRET} + redirect-uri: ${KAKAO_REDIRECT_URI} + client-authentication-method: client_secret_post + authorization-grant-type: authorization_code + client-name: Kakao + scope: + - profile_nickname + - profile_image + - account_email + provider: + kakao: + authorization-uri: ${KAKAO_AUTHORIZATION_URI} + token-uri: ${KAKAO_TOKEN_URI} + user-info-uri: ${KAKAO_USER_INFO_URI} + user-name-attribute: id + data: + redis: + host: ${REDIS_HOST} + port: ${REDIS_PORT} + + rabbitmq: + host: localhost + port: 5672 + username: ${RABBITMQ_USERNAME} + password: ${RABBITMQ_PASSWORD} + listener: + simple: + prefetch: 50 + +jwt: + secret-key: ${JWT_SECRET_KEY} + access: + expiration: 604800000 #3600000 #1hours + header: Authorization + refresh: + expiration: 604800000 #7days + header: Authorization-refresh + +rabbitmq: + summary: + queue.name: ${SUMMARY_QUEUE_NAME} + exchange.name: ${SUMMARY_EXCHANGE_NAME} + routing.key: ${SUMMARY_ROUTING_KEY} + store: + queue.name: ${STORE_QUEUE_NAME} + exchange.name: ${STORE_EXCHANGE_NAME} + routing.key: ${STORE_ROUTING_KEY} + +crawling: + quantity: 50 + +clova: + secret-key: ${CLOVA_SECRET_KEY} + client-id: ${CLOVA_CLIENT_ID} diff --git a/backend/core/src/test/resources/application.yml b/backend/core/src/test/resources/application.yml new file mode 100644 index 00000000..027b4e36 --- /dev/null +++ b/backend/core/src/test/resources/application.yml @@ -0,0 +1,3 @@ +spring: + profiles: + active: test \ No newline at end of file From c2596d1853d20cd7752e4da02a20262922c2ace1 Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 18:26:31 +0900 Subject: [PATCH 16/18] =?UTF-8?q?feat:=20nickname=20=EB=B3=80=EA=B2=BD=20a?= =?UTF-8?q?pi=20AuthController=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 --- .../domain/member/api/MemberController.java | 13 ------------- .../global/oauth2/controller/AuthController.java | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/member/api/MemberController.java b/backend/core/src/main/java/com/rollthedice/backend/domain/member/api/MemberController.java index 59284ff2..63411b19 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/member/api/MemberController.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/member/api/MemberController.java @@ -16,19 +16,6 @@ public class MemberController implements MemberApi{ private final MemberService memberService; - @PostMapping("") - public ResponseEntity updateMember(@LoginMemberEmail String email, - @RequestBody MemberUpdateDto memberUpdateDto) { - MemberServiceDto memberServiceDto = memberUpdateDto.toServiceDto(email); - - if (memberService.isDuplicatedNickname(memberServiceDto)) { - return ResponseEntity.status(HttpStatus.CONFLICT).build(); - } - memberService.update(memberServiceDto); - - return ResponseEntity.status(HttpStatus.OK).build(); - } - @ResponseStatus(HttpStatus.OK) @GetMapping("") @Override diff --git a/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/controller/AuthController.java b/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/controller/AuthController.java index 18a20501..5a38e5b1 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/controller/AuthController.java +++ b/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/controller/AuthController.java @@ -1,23 +1,38 @@ package com.rollthedice.backend.global.oauth2.controller; +import com.rollthedice.backend.domain.member.dto.MemberUpdateDto; +import com.rollthedice.backend.domain.member.service.MemberService; +import com.rollthedice.backend.global.annotation.LoginMemberEmail; import com.rollthedice.backend.global.oauth2.dto.LoginRequest; import com.rollthedice.backend.global.oauth2.service.AuthService; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +@Slf4j @RestController @RequiredArgsConstructor public class AuthController { private final AuthService authService; + private final MemberService memberService; @PostMapping("/login") public ResponseEntity login(@RequestBody LoginRequest request, HttpServletResponse response) { authService.authenticateOrRegisterUser(request, response); return new ResponseEntity<>(HttpStatus.OK); } + + @PostMapping("/oauth2/sign-up") + public ResponseEntity updateMember(@LoginMemberEmail String email, + @RequestBody MemberUpdateDto memberUpdateDto) { + memberService.update(memberUpdateDto); + + return ResponseEntity.status(HttpStatus.OK).build(); + } + } \ No newline at end of file From c61f0bd282b052ce5347d6643541d3955c95d6f2 Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 18:27:31 +0900 Subject: [PATCH 17/18] =?UTF-8?q?refactor:=20member=20update=20logic=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/member/service/MemberService.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/member/service/MemberService.java b/backend/core/src/main/java/com/rollthedice/backend/domain/member/service/MemberService.java index ea9e1072..1b5a1962 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/member/service/MemberService.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/member/service/MemberService.java @@ -1,6 +1,7 @@ package com.rollthedice.backend.domain.member.service; import com.rollthedice.backend.domain.member.dto.MemberServiceDto; +import com.rollthedice.backend.domain.member.dto.MemberUpdateDto; import com.rollthedice.backend.domain.member.dto.response.MemberResponse; import com.rollthedice.backend.domain.member.entity.Member; import com.rollthedice.backend.domain.member.exception.MemberNotFoundException; @@ -11,9 +12,11 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +@Slf4j @RequiredArgsConstructor @Service public class MemberService { @@ -27,8 +30,9 @@ public boolean isDuplicatedNickname(MemberServiceDto memberServiceDto) { } @Transactional - public void update(MemberServiceDto memberServiceDto) { - findByEmail(memberServiceDto.getEmail()).update(memberServiceDto); + public void update(MemberUpdateDto memberUpdateDto) { + Member loginMember = authService.getMember(); + loginMember.signUp(memberUpdateDto.getNickname()); } @Transactional(readOnly = true) From de9d3562016a15490e26bcb6517d59064fce172a Mon Sep 17 00:00:00 2001 From: yeonjy Date: Mon, 17 Jun 2024 18:27:55 +0900 Subject: [PATCH 18/18] =?UTF-8?q?fix:=20user=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EB=AA=A8=EB=91=90=20=EB=B0=9B=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/global/oauth2/OAuthAttributes.java | 2 +- .../backend/global/oauth2/service/AuthService.java | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/OAuthAttributes.java b/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/OAuthAttributes.java index f3aacaa1..2dfcb75c 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/OAuthAttributes.java +++ b/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/OAuthAttributes.java @@ -41,7 +41,7 @@ public Member toEntity(SocialType socialType, OAuth2UserInfo oauth2UserInfo) { .email(oauth2UserInfo.getEmail()) .nickname(oauth2UserInfo.getNickname()) .imageUrl(oauth2UserInfo.getImageUrl()) - .role(Role.GUEST) + .role(Role.USER) .status(Status.ACTIVE) .build(); } diff --git a/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/service/AuthService.java b/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/service/AuthService.java index 3d150356..85bcaef7 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/service/AuthService.java +++ b/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/service/AuthService.java @@ -41,8 +41,8 @@ private Member registerMember(SocialType socialType, OAuth2UserInfo userInfo) { Member member = Member.builder() .socialType(socialType) .oauthId(userInfo.getId()) - .email(UUID.randomUUID() + "@socialUser.com") - .nickname(String.valueOf(UUID.randomUUID())) + .email(userInfo.getEmail()) + .nickname(userInfo.getNickname()) .imageUrl(userInfo.getImageUrl()) .role(Role.USER) .build(); @@ -51,10 +51,9 @@ private Member registerMember(SocialType socialType, OAuth2UserInfo userInfo) { } public Member getMember() { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - UserDetails userDetails = (UserDetails) authentication.getPrincipal(); - return memberRepository.findByEmail(userDetails.getUsername()).orElseThrow(MemberNotFoundException::new); + String username = authentication.getName(); + return memberRepository.findByEmail(username).orElseThrow(MemberNotFoundException::new); } }