diff --git a/src/docs/asciidoc/user-api.adoc b/src/docs/asciidoc/user-api.adoc index 97283ed..aaf7f54 100644 --- a/src/docs/asciidoc/user-api.adoc +++ b/src/docs/asciidoc/user-api.adoc @@ -176,3 +176,27 @@ include::{snippetsDir}/userExit/1/http-response.adoc[] ==== Response Body Fields include::{snippetsDir}/userExit/1/response-fields.adoc[] + +=== **10. 북마크 생성 api** + +게시글 북마크를 생성 + +==== Request +include::{snippetsDir}/createBookmark/1/http-request.adoc[] + +==== Request Body Fields +include::{snippetsDir}/createBookmark/1/request-fields.adoc[] + +==== 성공 Response +성공 1. 북마크가 새롭게 생성된 경우 : CREATED +include::{snippetsDir}/createBookmark/1/http-response.adoc[] + +성공 2. 이미 존재하는 북마크에 대해 생성 요청을 보낸 경우 : OK +include::{snippetsDir}/createBookmark/2/http-response.adoc[] + +==== Response Body Fields +include::{snippetsDir}/createBookmark/1/response-fields.adoc[] + +==== 실패 Response +실패1. +include::{snippetsDir}/createBookmark/3/http-response.adoc[] \ No newline at end of file diff --git a/src/main/java/com/ftm/server/adapter/in/web/user/controller/CreateBookmarkController.java b/src/main/java/com/ftm/server/adapter/in/web/user/controller/CreateBookmarkController.java new file mode 100644 index 0000000..29dd81b --- /dev/null +++ b/src/main/java/com/ftm/server/adapter/in/web/user/controller/CreateBookmarkController.java @@ -0,0 +1,35 @@ +package com.ftm.server.adapter.in.web.user.controller; + +import com.ftm.server.adapter.in.web.user.dto.request.CreateBookmarkRequest; +import com.ftm.server.application.command.user.CreateBookmarkCommand; +import com.ftm.server.application.port.in.user.CreateBookmarkUseCase; +import com.ftm.server.common.response.ApiResponse; +import com.ftm.server.common.response.enums.SuccessResponseCode; +import com.ftm.server.infrastructure.security.UserPrincipal; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class CreateBookmarkController { + + private final CreateBookmarkUseCase createBookmarkUseCase; + + @PostMapping("/api/users/bookmarks") + public ResponseEntity createBookMark( + @AuthenticationPrincipal UserPrincipal user, + @RequestBody CreateBookmarkRequest request) { + Boolean isCreated = + createBookmarkUseCase.execute( + CreateBookmarkCommand.of(user.getId(), request.getPostId())); + HttpStatus httpStatus = isCreated ? HttpStatus.CREATED : HttpStatus.OK; + SuccessResponseCode successResponseCode = + isCreated ? SuccessResponseCode.CREATED : SuccessResponseCode.OK; + return ResponseEntity.status(httpStatus).body(ApiResponse.success(successResponseCode)); + } +} diff --git a/src/main/java/com/ftm/server/adapter/in/web/user/dto/request/CreateBookmarkRequest.java b/src/main/java/com/ftm/server/adapter/in/web/user/dto/request/CreateBookmarkRequest.java new file mode 100644 index 0000000..caafaaf --- /dev/null +++ b/src/main/java/com/ftm/server/adapter/in/web/user/dto/request/CreateBookmarkRequest.java @@ -0,0 +1,8 @@ +package com.ftm.server.adapter.in.web.user.dto.request; + +import lombok.Data; + +@Data +public class CreateBookmarkRequest { + private final Long postId; +} diff --git a/src/main/java/com/ftm/server/adapter/out/persistence/adapter/user/UserDomainPersistenceAdapter.java b/src/main/java/com/ftm/server/adapter/out/persistence/adapter/user/UserDomainPersistenceAdapter.java index b591311..d23ff91 100644 --- a/src/main/java/com/ftm/server/adapter/out/persistence/adapter/user/UserDomainPersistenceAdapter.java +++ b/src/main/java/com/ftm/server/adapter/out/persistence/adapter/user/UserDomainPersistenceAdapter.java @@ -1,9 +1,6 @@ package com.ftm.server.adapter.out.persistence.adapter.user; -import com.ftm.server.adapter.out.persistence.mapper.EmailVerificationLogsMapper; -import com.ftm.server.adapter.out.persistence.mapper.PostMapper; -import com.ftm.server.adapter.out.persistence.mapper.UserImageMapper; -import com.ftm.server.adapter.out.persistence.mapper.UserMapper; +import com.ftm.server.adapter.out.persistence.mapper.*; import com.ftm.server.adapter.out.persistence.model.*; import com.ftm.server.adapter.out.persistence.repository.*; import com.ftm.server.application.command.user.*; @@ -18,6 +15,7 @@ import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DataIntegrityViolationException; @Adapter @RequiredArgsConstructor @@ -38,7 +36,10 @@ public class UserDomainPersistenceAdapter DeleteUserImagePort, DeleteGroomingTestResultPort, DeleteUserPort, - DeleteBookmarkPort { + DeleteBookmarkPort, + SaveBookmarkPort, + CheckBookmarkPort, + CheckPostPort { // repository private final EmailVerificationLogsRepository emailVerificationLogsRepository; @@ -54,6 +55,7 @@ public class UserDomainPersistenceAdapter private final UserMapper userMapper; private final UserImageMapper userImageMapper; private final PostMapper postMapper; + private final BookmarkMapper bookmarkMapper; @Override public Optional loadEmailVerificationLogByEmail(FindByEmailQuery query) { @@ -110,6 +112,11 @@ public Boolean checksUserBySocialValue(FindBySocialValueQuery query) { query.getSocialId(), query.getSocialProvider()); } + @Override + public Boolean checksUserById(FindByUserIdQuery query) { + return userRepository.existsById(query.getUserId()); + } + @Override public User saveSocialUser(User user) { UserJpaEntity userJpaEntity = userMapper.toJpaEntity(user, null); @@ -223,4 +230,30 @@ public void deleteAllUserByIdList(DeleteAllUserByIdListCommand command) { public void deleteBookmarkByUserList(DeleteBookmarkByUserIdCommand command) { bookmarkRepository.deleteAllByUserIdList(command.getUserIdList()); } + + @Override + public Boolean saveBookmark(Bookmark bookmark) { + // 이미 생성된 북마크인 경우 -> false + // 새롭게 생성된 북마크인 경우 -> true + int isCreated; + try { + isCreated = bookmarkRepository.saveOrUpdate(bookmark.getUserId(), bookmark.getPostId()); + } catch ( + DataIntegrityViolationException + e) { // on conflict로 문제 예방 했지만, 동시성 문제로 unique key 위반 에러 나는 경우, 에러 반환하지 않고 + // 그냥 처리(북마크 생성하지 않고 OK 반환) + return false; + } + return isCreated == 1; + } + + @Override + public Boolean checkIfBookmarkExists(FindBookmarkByUserIdAndPostIdQuery query) { + return bookmarkRepository.existsByUserIdAndPostId(query.getUserId(), query.getPostId()); + } + + @Override + public Boolean checksPostById(FindByPostIdQuery query) { + return postRepository.existsById(query.getPostId()); + } } diff --git a/src/main/java/com/ftm/server/adapter/out/persistence/repository/BookmarkRepository.java b/src/main/java/com/ftm/server/adapter/out/persistence/repository/BookmarkRepository.java index ce651d8..ed3eaab 100644 --- a/src/main/java/com/ftm/server/adapter/out/persistence/repository/BookmarkRepository.java +++ b/src/main/java/com/ftm/server/adapter/out/persistence/repository/BookmarkRepository.java @@ -11,4 +11,16 @@ public interface BookmarkRepository extends JpaRepository userIds); + + @Modifying + @Query( + value = + "INSERT INTO bookmark (user_id, post_id) " + + "VALUES (:userId, :postId) " + + "ON CONFLICT (user_id, post_id) " + + "DO NOTHING;", + nativeQuery = true) + int saveOrUpdate(@Param("userId") Long userId, @Param("postId") Long postId); + + Boolean existsByUserIdAndPostId(Long userId, Long postId); } diff --git a/src/main/java/com/ftm/server/adapter/out/persistence/repository/PostRepository.java b/src/main/java/com/ftm/server/adapter/out/persistence/repository/PostRepository.java index 25ee8f4..87b2d43 100644 --- a/src/main/java/com/ftm/server/adapter/out/persistence/repository/PostRepository.java +++ b/src/main/java/com/ftm/server/adapter/out/persistence/repository/PostRepository.java @@ -14,4 +14,6 @@ public interface PostRepository extends JpaRepository, Post @Modifying @Query("DELETE FROM PostJpaEntity p WHERE p.id IN (:postIds)") void deleteAllByIdInBatch(@Param("postIds") List postIds); + + boolean existsById(Long id); } diff --git a/src/main/java/com/ftm/server/application/command/user/CreateBookmarkCommand.java b/src/main/java/com/ftm/server/application/command/user/CreateBookmarkCommand.java new file mode 100644 index 0000000..9f6fc14 --- /dev/null +++ b/src/main/java/com/ftm/server/application/command/user/CreateBookmarkCommand.java @@ -0,0 +1,13 @@ +package com.ftm.server.application.command.user; + +import lombok.Data; + +@Data +public class CreateBookmarkCommand { + private final Long userId; + private final Long postId; + + public static CreateBookmarkCommand of(Long userId, Long postId) { + return new CreateBookmarkCommand(userId, postId); + } +} diff --git a/src/main/java/com/ftm/server/application/port/in/user/CreateBookmarkUseCase.java b/src/main/java/com/ftm/server/application/port/in/user/CreateBookmarkUseCase.java new file mode 100644 index 0000000..2d92f62 --- /dev/null +++ b/src/main/java/com/ftm/server/application/port/in/user/CreateBookmarkUseCase.java @@ -0,0 +1,9 @@ +package com.ftm.server.application.port.in.user; + +import com.ftm.server.application.command.user.CreateBookmarkCommand; +import com.ftm.server.common.annotation.UseCase; + +@UseCase +public interface CreateBookmarkUseCase { + Boolean execute(CreateBookmarkCommand command); +} diff --git a/src/main/java/com/ftm/server/application/port/out/persistence/user/CheckBookmarkPort.java b/src/main/java/com/ftm/server/application/port/out/persistence/user/CheckBookmarkPort.java new file mode 100644 index 0000000..ead5466 --- /dev/null +++ b/src/main/java/com/ftm/server/application/port/out/persistence/user/CheckBookmarkPort.java @@ -0,0 +1,10 @@ +package com.ftm.server.application.port.out.persistence.user; + +import com.ftm.server.application.query.FindBookmarkByUserIdAndPostIdQuery; +import com.ftm.server.common.annotation.Port; + +@Port +public interface CheckBookmarkPort { + + Boolean checkIfBookmarkExists(FindBookmarkByUserIdAndPostIdQuery query); +} diff --git a/src/main/java/com/ftm/server/application/port/out/persistence/user/CheckPostPort.java b/src/main/java/com/ftm/server/application/port/out/persistence/user/CheckPostPort.java new file mode 100644 index 0000000..1fd9cc1 --- /dev/null +++ b/src/main/java/com/ftm/server/application/port/out/persistence/user/CheckPostPort.java @@ -0,0 +1,7 @@ +package com.ftm.server.application.port.out.persistence.user; + +import com.ftm.server.application.query.FindByPostIdQuery; + +public interface CheckPostPort { + Boolean checksPostById(FindByPostIdQuery query); +} diff --git a/src/main/java/com/ftm/server/application/port/out/persistence/user/CheckUserPort.java b/src/main/java/com/ftm/server/application/port/out/persistence/user/CheckUserPort.java index 1aa8f4d..1444af9 100644 --- a/src/main/java/com/ftm/server/application/port/out/persistence/user/CheckUserPort.java +++ b/src/main/java/com/ftm/server/application/port/out/persistence/user/CheckUserPort.java @@ -2,6 +2,7 @@ import com.ftm.server.application.query.FindByEmailQuery; import com.ftm.server.application.query.FindBySocialValueQuery; +import com.ftm.server.application.query.FindByUserIdQuery; import com.ftm.server.common.annotation.Port; @Port @@ -9,4 +10,6 @@ public interface CheckUserPort { Boolean checksUserByEmail(FindByEmailQuery query); Boolean checksUserBySocialValue(FindBySocialValueQuery query); + + Boolean checksUserById(FindByUserIdQuery query); } diff --git a/src/main/java/com/ftm/server/application/port/out/persistence/user/SaveBookmarkPort.java b/src/main/java/com/ftm/server/application/port/out/persistence/user/SaveBookmarkPort.java new file mode 100644 index 0000000..41b77b7 --- /dev/null +++ b/src/main/java/com/ftm/server/application/port/out/persistence/user/SaveBookmarkPort.java @@ -0,0 +1,9 @@ +package com.ftm.server.application.port.out.persistence.user; + +import com.ftm.server.common.annotation.Port; +import com.ftm.server.domain.entity.Bookmark; + +@Port +public interface SaveBookmarkPort { + Boolean saveBookmark(Bookmark bookmark); +} diff --git a/src/main/java/com/ftm/server/application/query/FindBookmarkByUserIdAndPostIdQuery.java b/src/main/java/com/ftm/server/application/query/FindBookmarkByUserIdAndPostIdQuery.java new file mode 100644 index 0000000..2c95e04 --- /dev/null +++ b/src/main/java/com/ftm/server/application/query/FindBookmarkByUserIdAndPostIdQuery.java @@ -0,0 +1,13 @@ +package com.ftm.server.application.query; + +import lombok.Data; + +@Data +public class FindBookmarkByUserIdAndPostIdQuery { + private final Long userId; + private final Long postId; + + public static FindBookmarkByUserIdAndPostIdQuery of(Long userId, Long postId) { + return new FindBookmarkByUserIdAndPostIdQuery(userId, postId); + } +} diff --git a/src/main/java/com/ftm/server/application/service/user/CreateBookmarkService.java b/src/main/java/com/ftm/server/application/service/user/CreateBookmarkService.java new file mode 100644 index 0000000..782146d --- /dev/null +++ b/src/main/java/com/ftm/server/application/service/user/CreateBookmarkService.java @@ -0,0 +1,54 @@ +package com.ftm.server.application.service.user; + +import com.ftm.server.application.command.user.CreateBookmarkCommand; +import com.ftm.server.application.port.in.user.CreateBookmarkUseCase; +import com.ftm.server.application.port.out.persistence.user.*; +import com.ftm.server.application.query.FindBookmarkByUserIdAndPostIdQuery; +import com.ftm.server.application.query.FindByPostIdQuery; +import com.ftm.server.application.query.FindByUserIdQuery; +import com.ftm.server.common.exception.CustomException; +import com.ftm.server.common.response.enums.ErrorResponseCode; +import com.ftm.server.domain.entity.Bookmark; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class CreateBookmarkService implements CreateBookmarkUseCase { + + private final CheckUserPort checkUserPort; + private final CheckPostPort checkPostPort; + private final SaveBookmarkPort saveBookmarkPort; + private final CheckBookmarkPort checkBookmarkPort; + + @Override + @Transactional + public Boolean execute(CreateBookmarkCommand command) { + // user id와 post id 유효성 검사-> 없는 경우 exception 반환 + Boolean userExists = + checkUserPort.checksUserById(FindByUserIdQuery.of(command.getUserId())); + Boolean postExists = + checkPostPort.checksPostById(FindByPostIdQuery.of(command.getPostId())); + if (!userExists) { + throw CustomException.USER_NOT_FOUND; + } + if (!postExists) { + throw new CustomException(ErrorResponseCode.POST_NOT_FOUND); + } + + // 북마크 기존에 존재하는지 확인(중복 생성 방지) + if (checkBookmarkPort.checkIfBookmarkExists( + FindBookmarkByUserIdAndPostIdQuery.of(command.getUserId(), command.getPostId()))) { + return false; + } + // 북마크 생성 후 저장 + Bookmark bookmark = Bookmark.createBookmark(command.getUserId(), command.getPostId()); + + // 북마크 존재하는지 검사 후 - 북마크 저장 과정 사이에 북마크가 생성되어 중복 생성되는 것을 막고자 + // sql 단에서 한번 더 검사 진행 + // -> 이미 동일한 북마크가 존재할 경우 do nothing & false 반환 + // -> 동일한 북마크가 없어서 새로 생성&저장한 경우 true 반환 + return saveBookmarkPort.saveBookmark(bookmark); + } +} diff --git a/src/main/java/com/ftm/server/domain/entity/Bookmark.java b/src/main/java/com/ftm/server/domain/entity/Bookmark.java index 6966afd..60a75ec 100644 --- a/src/main/java/com/ftm/server/domain/entity/Bookmark.java +++ b/src/main/java/com/ftm/server/domain/entity/Bookmark.java @@ -34,4 +34,8 @@ public static Bookmark of( .updatedAt(updatedAt) .build(); } + + public static Bookmark createBookmark(Long userId, Long postId) { + return Bookmark.builder().userId(userId).postId(postId).build(); + } } diff --git a/src/test/java/com/ftm/server/BaseTest.java b/src/test/java/com/ftm/server/BaseTest.java index 1fa1874..a4c483f 100644 --- a/src/test/java/com/ftm/server/BaseTest.java +++ b/src/test/java/com/ftm/server/BaseTest.java @@ -142,4 +142,32 @@ protected MockHttpSession login(String email) { return session; } + + public record SessionAndUser(MockHttpSession mockHttpSession, User user) {} + + // Session과 함께 User도 반환 + protected SessionAndUser createUserAndLoginAndReturnUser() { + return createUserAndLoginAndReturnUser("test@gmail.com", "123456qwe!"); + } + + protected SessionAndUser createUserAndLoginAndReturnUser(String email, String password) { + + // 사용자 생성 + User user = createTestUser(email, password); + + // session 생성 + SecurityContext context = SecurityContextHolder.createEmptyContext(); + UsernamePasswordAuthenticationToken auth = + new UsernamePasswordAuthenticationToken( + UserPrincipal.of(user), + null, + List.of(new SimpleGrantedAuthority(UserRole.USER.name()))); + context.setAuthentication(auth); + + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, context); + + return new SessionAndUser(session, user); + } } diff --git a/src/test/java/com/ftm/server/user/CreateBookmarkTest.java b/src/test/java/com/ftm/server/user/CreateBookmarkTest.java new file mode 100644 index 0000000..0e55f8b --- /dev/null +++ b/src/test/java/com/ftm/server/user/CreateBookmarkTest.java @@ -0,0 +1,191 @@ +package com.ftm.server.user; + +import static com.epages.restdocs.apispec.ResourceDocumentation.resource; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.JsonFieldType.NUMBER; +import static org.springframework.restdocs.payload.PayloadDocumentation.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.epages.restdocs.apispec.ResourceSnippetParameters; +import com.ftm.server.BaseTest; +import com.ftm.server.adapter.in.web.post.dto.request.SavePostRequest; +import com.ftm.server.adapter.in.web.user.dto.request.CreateBookmarkRequest; +import com.ftm.server.adapter.out.persistence.repository.BookmarkRepository; +import com.ftm.server.application.command.post.SavePostCommand; +import com.ftm.server.application.port.in.user.CreateBookmarkUseCase; +import com.ftm.server.application.port.out.persistence.post.SavePostPort; +import com.ftm.server.application.port.out.persistence.user.SaveBookmarkPort; +import com.ftm.server.common.response.enums.ErrorResponseCode; +import com.ftm.server.domain.entity.Bookmark; +import com.ftm.server.domain.entity.Post; +import com.ftm.server.domain.entity.User; +import com.ftm.server.domain.enums.GroomingCategory; +import jakarta.transaction.Transactional; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; +import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; +import org.springframework.restdocs.payload.FieldDescriptor; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.DefaultTransactionDefinition; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class CreateBookmarkTest extends BaseTest { + + @Autowired private PlatformTransactionManager transactionManager; + + private TransactionStatus transactionStatus; + + @Autowired private SavePostPort savePostPort; + @Autowired private SaveBookmarkPort saveBookmarkPort; + @Autowired private CreateBookmarkUseCase createBookmarkUseCase; + @Autowired private BookmarkRepository bookmarkRepository; + + private static MockHttpSession session; + private static User user; + private static Post post; + + private final List responseFieldDescriptors = + List.of( + fieldWithPath("status").type(NUMBER).description("응답 상태"), + fieldWithPath("code").type(JsonFieldType.STRING).description("상태 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("메시지"), + fieldWithPath("data") + .type(JsonFieldType.OBJECT) + .optional() + .description("data")); + private final List requestFieldDescriptors = + List.of(fieldWithPath("postId").type(NUMBER).description("북마크 생성 게시글 id")); + + private ResultActions getResultActions(MockHttpSession session, CreateBookmarkRequest request) + throws Exception { + return mockMvc.perform( // api 실행 + RestDocumentationRequestBuilders.post("/api/users/bookmarks") + .content(mapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON) + .session(session)); + } + + // 문서화 반환 함수 + private RestDocumentationResultHandler getDocument(Integer identifier) { + return document( + "createBookmark/" + identifier, + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint(), getModifiedHeader()), + responseFields(responseFieldDescriptors), + requestFields(requestFieldDescriptors), + resource( + ResourceSnippetParameters.builder() + .tag("회원") + .summary("북마크 생성 api") + .description("북마크를 생성합니다.") + .responseFields(responseFieldDescriptors) + .build())); + } + + @BeforeAll + public void startTransaction() { + // 수동으로 트랜잭션 시작 + DefaultTransactionDefinition def = new DefaultTransactionDefinition(); + def.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED); + // 트랜잭션 시작 + transactionStatus = transactionManager.getTransaction(def); + + SessionAndUser sessionAndUser = createUserAndLoginAndReturnUser(); // 로그인 처리 + session = sessionAndUser.mockHttpSession(); + user = sessionAndUser.user(); + + // test 용 post 생성 + post = + savePostPort.savePost( + Post.create( + SavePostCommand.from( + user.getId(), + new SavePostRequest( + "test", + GroomingCategory.FASHION, + new ArrayList<>(), + "content", + new ArrayList<>()), + new ArrayList<>(), + new ArrayList<>()))); + } + + @AfterAll + public void rollbackTransaction() { + // 트랜잭션 롤백 + if (transactionStatus != null) { + transactionManager.rollback(transactionStatus); + } + } + + @Test + @Transactional + @DisplayName("북마크 생성 성공1") + void test1() throws Exception { + + // when + ResultActions resultActions = + getResultActions(session, new CreateBookmarkRequest(post.getId())); + + // then + resultActions.andExpect(status().isCreated()); + + // documentation + resultActions.andDo(getDocument(1)); + } + + @Test + @Transactional + @DisplayName("북마크 생성 성공2") + void test2() throws Exception { + // given + saveBookmarkPort.saveBookmark(Bookmark.createBookmark(user.getId(), post.getId())); + + // when + ResultActions resultActions = + getResultActions(session, new CreateBookmarkRequest(post.getId())); + + // then + resultActions.andExpect(status().isOk()); + + // documentation + resultActions.andDo(getDocument(2)); + } + + @Test + @Transactional + @DisplayName("북마크 생성 실패") + void test3() throws Exception { + // when + ResultActions resultActions = getResultActions(session, new CreateBookmarkRequest(10L)); + + // then + resultActions + .andExpect(status().is(ErrorResponseCode.POST_NOT_FOUND.getHttpStatus().value())) + .andExpect(jsonPath("code").value(ErrorResponseCode.POST_NOT_FOUND.getCode())); + + // documentation + resultActions.andDo(getDocument(3)); + } + + @Test + @Transactional + @DisplayName("레파지토리 테스트") + void test4() { + saveBookmarkPort.saveBookmark(Bookmark.createBookmark(user.getId(), post.getId())); + int result = bookmarkRepository.saveOrUpdate(user.getId(), post.getId()); + assertThat(result).isEqualTo(0); + } +}