diff --git a/Owing-Api/src/test/java/com/owing/api/project/service/CreateProjectUseCaseTest.java b/Owing-Api/src/test/java/com/owing/api/project/service/CreateProjectUseCaseTest.java new file mode 100644 index 00000000..a0416099 --- /dev/null +++ b/Owing-Api/src/test/java/com/owing/api/project/service/CreateProjectUseCaseTest.java @@ -0,0 +1,164 @@ +package com.owing.api.project.service; + +import com.owing.api.project.model.dto.request.AddProjectRequest; +import com.owing.api.project.model.dto.response.ProjectShortInfoResponse; +import com.owing.common.util.MemberUtils; +import com.owing.entity.domains.member.model.Member; +import com.owing.entity.domains.member.model.OauthProvider; +import com.owing.entity.domains.member.repository.MemberRepository; +import com.owing.entity.domains.project.model.Category; +import com.owing.entity.domains.project.model.Project; +import com.owing.entity.domains.project.repository.ProjectRepository; +import com.owing.entity.domains.story.repository.StoryFolderRepository; +import com.owing.entity.domains.universe.repository.UniverseFolderRepository; +import com.owing.node.domains.project.model.ProjectNode; +import com.owing.node.domains.project.repository.ProjectNodeRepository; +import io.github.cdimascio.dotenv.Dotenv; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.data.neo4j.core.Neo4jClient; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.springframework.transaction.annotation.Transactional; + +import java.util.HashSet; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; + +@ActiveProfiles("test") +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@SpringBootTest +class CreateProjectUseCaseTest { + + @MockBean + private MemberUtils memberUtils; + @SpyBean + private ProjectNodeRepository projectNodeRepository; + + @Autowired + private CreateProjectUseCase createProjectUseCase; + @Autowired + private MemberRepository memberRepository; + @Autowired + private ProjectRepository projectRepository; + + private Member testMember; + @Autowired + private Neo4jClient neo4jClient; + @Autowired + private StoryFolderRepository storyFolderRepository; + @Autowired + private UniverseFolderRepository universeFolderRepository; + + @DynamicPropertySource + static void loadProperties(DynamicPropertyRegistry registry) { + Dotenv dotenv = Dotenv.configure() + .directory("../") + .filename(".env") // .env 파일의 경로를 필요에 따라 지정 + .ignoreIfMissing() // .env 파일이 없으면 무시 + .load(); + + dotenv.entries().forEach(entry -> { + registry.add(entry.getKey(), entry.getValue()::toString); + }); + } + + @BeforeEach + void setUp() { + // 테스트 전용 멤버를 직접 DB에 저장 + testMember = Member.builder() + .email("test@integration.com") + .password("integration1234") + .name("테스트유저") + .nickname("integUser") + .provider(OauthProvider.KAKAO) + .build(); + memberRepository.save(testMember); + + Mockito.reset(memberUtils, projectNodeRepository); + } + + @AfterEach + void tearDown() { + storyFolderRepository.deleteAllInBatch(); + universeFolderRepository.deleteAllInBatch(); + projectRepository.deleteAllInBatch(); + memberRepository.deleteAllInBatch(); + + if (neo4jClient == null) { + throw new IllegalStateException("Neo4jClient is null, cannot clean up Neo4j DB."); + } + neo4jClient.query("MATCH (n) DETACH DELETE n;").run(); + } + + @Test + @DisplayName("Project 생성 시 Entuty와 Node가 함께 생성된다.") + void createProjectUseCase() { + // given + when(memberUtils.getCurrentMemberReference()) + .thenReturn(testMember); + + AddProjectRequest request = new AddProjectRequest( + "Integration Project", + "Integration Test Desc", + Category.ESSAY, + new HashSet<>(), + null + ); + + // when + ProjectShortInfoResponse res = createProjectUseCase.execute(request); + + // then + assertThat(res.project().title()).isEqualTo(request.title()); + + Optional savedProject = projectRepository.findById(res.project().id()); + assertThat(savedProject).isPresent(); + + Optional savedProjectNode = projectNodeRepository.findById(res.project().id()); + assertThat(savedProjectNode).isPresent(); + } + + @Test + @DisplayName("Project 생성 시 Node생성이 실페하면 모두 롤백된다.") + void createProjectUseCaseWithNodeFail() { + // given + when(memberUtils.getCurrentMemberReference()) + .thenReturn(testMember); + doThrow(new RuntimeException()).when(projectNodeRepository).save(any(ProjectNode.class)); + + AddProjectRequest request = new AddProjectRequest( + "Integration Project", + "Integration Test Desc", + Category.ESSAY, + new HashSet<>(), + null + ); + + // when, then + assertThatThrownBy(() -> createProjectUseCase.execute(request)) + .isInstanceOf(RuntimeException.class); + + List projects = projectRepository.findAll(); + assertThat(projects).isEmpty(); + + List projectNodes = projectNodeRepository.findAll(); + assertThat(projectNodes).isEmpty(); + } + +} \ No newline at end of file diff --git a/Owing-Api/src/test/java/com/owing/api/project/service/DeleteProjectUseCaseTest.java b/Owing-Api/src/test/java/com/owing/api/project/service/DeleteProjectUseCaseTest.java new file mode 100644 index 00000000..44c132f0 --- /dev/null +++ b/Owing-Api/src/test/java/com/owing/api/project/service/DeleteProjectUseCaseTest.java @@ -0,0 +1,167 @@ +package com.owing.api.project.service; + +import com.owing.api.project.model.dto.request.AddProjectRequest; +import com.owing.api.project.model.dto.response.ProjectShortInfoResponse; +import com.owing.common.util.MemberUtils; +import com.owing.entity.domains.member.model.Member; +import com.owing.entity.domains.member.model.OauthProvider; +import com.owing.entity.domains.member.repository.MemberRepository; +import com.owing.entity.domains.project.error.ProjectErrorCode; +import com.owing.entity.domains.project.error.exception.ProjectIllegalAccessException; +import com.owing.entity.domains.project.model.Category; +import com.owing.entity.domains.project.model.Project; +import com.owing.entity.domains.project.repository.ProjectRepository; +import com.owing.entity.domains.story.repository.StoryFolderRepository; +import com.owing.entity.domains.universe.repository.UniverseFolderRepository; +import com.owing.node.domains.project.adapter.ProjectNodeAdapter; +import com.owing.node.domains.project.error.code.ProjectNodeErrorCode; +import com.owing.node.domains.project.error.exception.ProjectNodeNotFoundException; +import com.owing.node.domains.project.repository.ProjectNodeRepository; +import io.github.cdimascio.dotenv.Dotenv; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.data.neo4j.core.Neo4jClient; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; + +import java.util.HashSet; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.when; + +@ActiveProfiles("test") +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@SpringBootTest +class DeleteProjectUseCaseTest { + + @MockBean + private MemberUtils memberUtils; + @SpyBean + private ProjectNodeRepository projectNodeRepository; + + @Autowired + private DeleteProjectUseCase deleteProjectUseCase; + @Autowired + private CreateProjectUseCase createProjectUseCase; + @Autowired + private MemberRepository memberRepository; + @Autowired + private ProjectRepository projectRepository; + + private Member testMember; + @Autowired + private ProjectNodeAdapter projectNodeAdapter; + @Autowired + private Neo4jClient neo4jClient; + @Autowired + private StoryFolderRepository storyFolderRepository; + @Autowired + private UniverseFolderRepository universeFolderRepository; + @Autowired + private JdbcTemplate jdbcTemplate; + + @DynamicPropertySource + static void loadProperties(DynamicPropertyRegistry registry) { + Dotenv dotenv = Dotenv.configure() + .directory("../") + .filename(".env") // .env 파일의 경로를 필요에 따라 지정 + .ignoreIfMissing() // .env 파일이 없으면 무시 + .load(); + + dotenv.entries().forEach(entry -> { + registry.add(entry.getKey(), entry.getValue()::toString); + }); + } + + @BeforeEach + void setUp() { + testMember = Member.builder() + .email("test@integration.com") + .password("integration1234") + .name("테스트유저") + .nickname("integUser") + .provider(OauthProvider.KAKAO) + .build(); + memberRepository.save(testMember); + + Mockito.reset(memberUtils, projectNodeRepository); + } + + @AfterEach + void tearDown() { + storyFolderRepository.deleteAllInBatch(); + universeFolderRepository.deleteAllInBatch(); + jdbcTemplate.execute("DELETE FROM project"); + memberRepository.deleteAllInBatch(); + + if (neo4jClient == null) { + throw new IllegalStateException("Neo4jClient is null, cannot clean up Neo4j DB."); + } + neo4jClient.query("MATCH (n) DETACH DELETE n;").run(); + } + + + @Test + @DisplayName("Project 삭제 시 Entuty와 Node가 함께 삭제된다.") + void deleteProjectUseCase() { + // given + when(memberUtils.getCurrentMemberReference()) + .thenReturn(testMember); + when(memberUtils.getCurrentMemberId()) + .thenReturn(testMember.getId()); + ProjectShortInfoResponse projectInfo = createProjectUseCase.execute(new AddProjectRequest( + "Integration Project", + "Integration Test Desc", + Category.ESSAY, + new HashSet<>(), + null + )); + Long projectId = projectInfo.project().id(); + + // when + deleteProjectUseCase.execute(projectId); + + // then + Optional projects = projectRepository.findById(projectId); + assertThat(projects).isEmpty(); + + assertThatThrownBy(() -> projectNodeAdapter.findById(projectId)) + .isInstanceOf(ProjectNodeNotFoundException.class) + .hasMessage(ProjectNodeErrorCode.PROJECT_NODE_NOT_FOUND.getMessage()); + } + + @Test + @DisplayName("Project 삭제 시 작성자와 다른 유저라면 예외가 발생한다.") + void deleteProjectUseCaseWithIllegalMember() { + // given + when(memberUtils.getCurrentMemberReference()) + .thenReturn(testMember); + when(memberUtils.getCurrentMemberId()) + .thenReturn(0L); + ProjectShortInfoResponse projectInfo = createProjectUseCase.execute(new AddProjectRequest( + "Integration Project", + "Integration Test Desc", + Category.ESSAY, + new HashSet<>(), + null + )); + Long projectId = projectInfo.project().id(); + + // when, then + assertThatThrownBy(() -> deleteProjectUseCase.execute(projectId)) + .isInstanceOf(ProjectIllegalAccessException.class) + .hasMessage(ProjectErrorCode.ILLEGAL_ACCESS.getMessage()); + } +} \ No newline at end of file diff --git a/Owing-Api/src/test/java/com/owing/api/project/service/ReadProjectListUseCaseTest.java b/Owing-Api/src/test/java/com/owing/api/project/service/ReadProjectListUseCaseTest.java new file mode 100644 index 00000000..e5c2bf78 --- /dev/null +++ b/Owing-Api/src/test/java/com/owing/api/project/service/ReadProjectListUseCaseTest.java @@ -0,0 +1,190 @@ +package com.owing.api.project.service; + +import com.owing.api.project.model.dto.request.AddProjectRequest; +import com.owing.api.project.model.dto.response.ProjectInfoResponse; +import com.owing.api.project.model.dto.response.ProjectShortInfoPageResponse; +import com.owing.api.project.model.dto.response.ProjectShortInfoResponse; +import com.owing.common.constant.ProjectSort; +import com.owing.common.util.MemberUtils; +import com.owing.entity.domains.member.model.Member; +import com.owing.entity.domains.member.model.OauthProvider; +import com.owing.entity.domains.member.repository.MemberRepository; +import com.owing.entity.domains.project.model.Category; +import com.owing.entity.domains.project.repository.ProjectRepository; +import com.owing.entity.domains.story.repository.StoryFolderRepository; +import com.owing.entity.domains.universe.repository.UniverseFolderRepository; +import com.owing.node.domains.project.repository.ProjectNodeRepository; +import io.github.cdimascio.dotenv.Dotenv; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.data.neo4j.core.Neo4jClient; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import static com.owing.common.constant.OwingApiConst.PAGE_DEFAULT; +import static com.owing.common.constant.OwingApiConst.PAGE_SIZE_DEFAULT; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +@ActiveProfiles("test") +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@SpringBootTest +class ReadProjectUseCaseTest { + + private Member testMember; + + @MockBean + private MemberUtils memberUtils; + @SpyBean + private ProjectNodeRepository projectNodeRepository; + + @Autowired + private CreateProjectUseCase createProjectUseCase; + @Autowired + private MemberRepository memberRepository; + @Autowired + private StoryFolderRepository storyFolderRepository; + @Autowired + private UniverseFolderRepository universeFolderRepository; + @Autowired + private ProjectRepository projectRepository; + @Autowired + private Neo4jClient neo4jClient; + @Autowired + private ReadProjectListUseCase readProjectListUseCase; + @Autowired + private ReadProjectUseCase readProjectUseCase; + + @DynamicPropertySource + static void loadProperties(DynamicPropertyRegistry registry) { + Dotenv dotenv = Dotenv.configure() + .directory("../") + .filename(".env") // .env 파일의 경로를 필요에 따라 지정 + .ignoreIfMissing() // .env 파일이 없으면 무시 + .load(); + + dotenv.entries().forEach(entry -> { + registry.add(entry.getKey(), entry.getValue()::toString); + }); + } + + @BeforeEach + void setUp() { + testMember = Member.builder() + .email("test@integration.com") + .password("integration1234") + .name("테스트유저") + .nickname("integUser") + .provider(OauthProvider.KAKAO) + .build(); + memberRepository.save(testMember); + + Mockito.reset(memberUtils, projectNodeRepository); + } + + @AfterEach + void tearDown() { + storyFolderRepository.deleteAllInBatch(); + universeFolderRepository.deleteAllInBatch(); + projectRepository.deleteAllInBatch(); + memberRepository.deleteAllInBatch(); + + if (neo4jClient == null) { + throw new IllegalStateException("Neo4jClient is null, cannot clean up Neo4j DB."); + } + neo4jClient.query("MATCH (n) DETACH DELETE n;").run(); + } + + @Test + @DisplayName("프로젝트 목록이 페이징되어 조회된다.") + void readProjectList() { + // given + when(memberUtils.getCurrentMemberReference()).thenReturn(testMember); + when(memberUtils.getCurrentMemberId()).thenReturn(testMember.getId()); + for (int i = 1; i <= 20; i++) { + createProjectUseCase.execute(new AddProjectRequest( + "Test 프로젝트" + i, + "Test Desc" + i, + Category.ESSAY, + new HashSet<>(), + null + )); + } + + int defaultPage = Integer.parseInt(PAGE_DEFAULT); + int defaultSize = Integer.parseInt(PAGE_SIZE_DEFAULT); + + // when + ProjectShortInfoPageResponse projectList = readProjectListUseCase.execute( + defaultPage, + defaultSize, + ProjectSort.ACCESSED_AT + ); + + // then + assertThat(projectList.projectList()).hasSize(defaultSize); + } + + // 없을 경우 0개 + @Test + @DisplayName("프로젝트가 없는 사용자라면 빈 리스트가 조회된다.") + void readProjectListWithEmptyList() { + // given + when(memberUtils.getCurrentMemberReference()).thenReturn(testMember); + when(memberUtils.getCurrentMemberId()).thenReturn(testMember.getId()); + + int defaultPage = Integer.parseInt(PAGE_DEFAULT); + int defaultSize = Integer.parseInt(PAGE_SIZE_DEFAULT); + + // when + ProjectShortInfoPageResponse projectList = readProjectListUseCase.execute( + defaultPage, + defaultSize, + ProjectSort.ACCESSED_AT + ); + + // then + assertThat(projectList.projectList()).isEmpty(); + } + + @Test + @DisplayName("프로젝트가 상세 정보가 조회된다.") + void readProject() { + // given + when(memberUtils.getCurrentMemberReference()).thenReturn(testMember); + when(memberUtils.getCurrentMemberId()).thenReturn(testMember.getId()); + + List savedProjectList = new ArrayList<>(); + for (int i = 1; i <= 5; i++) { + ProjectShortInfoResponse savedProject = createProjectUseCase.execute(new AddProjectRequest( + "Test 프로젝트" + i, + "Test Desc" + i, + Category.ESSAY, + new HashSet<>(), + null + )); + savedProjectList.add(savedProject); + } + + long targetProjectId = savedProjectList.getLast().project().id(); + + // when + ProjectInfoResponse result = readProjectUseCase.execute(targetProjectId); + + // then + assertThat(result.id()).isEqualTo(targetProjectId); + } +} \ No newline at end of file diff --git a/Owing-Api/src/test/java/com/owing/api/project/service/UpdateProjectUseCaseTest.java b/Owing-Api/src/test/java/com/owing/api/project/service/UpdateProjectUseCaseTest.java new file mode 100644 index 00000000..5b9bed39 --- /dev/null +++ b/Owing-Api/src/test/java/com/owing/api/project/service/UpdateProjectUseCaseTest.java @@ -0,0 +1,175 @@ +package com.owing.api.project.service; + +import com.owing.api.project.model.dto.request.AddProjectRequest; +import com.owing.api.project.model.dto.request.UpdateProjectRequest; +import com.owing.api.project.model.dto.response.ProjectShortInfoResponse; +import com.owing.common.util.MemberUtils; +import com.owing.entity.domains.member.model.Member; +import com.owing.entity.domains.member.model.OauthProvider; +import com.owing.entity.domains.member.repository.MemberRepository; +import com.owing.entity.domains.project.adapter.ProjectAdapter; +import com.owing.entity.domains.project.error.ProjectErrorCode; +import com.owing.entity.domains.project.error.exception.ProjectIllegalAccessException; +import com.owing.entity.domains.project.model.Category; +import com.owing.entity.domains.project.model.Project; +import com.owing.entity.domains.project.repository.ProjectRepository; +import com.owing.entity.domains.story.repository.StoryFolderRepository; +import com.owing.entity.domains.universe.repository.UniverseFolderRepository; +import com.owing.node.domains.project.repository.ProjectNodeRepository; +import io.github.cdimascio.dotenv.Dotenv; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.data.neo4j.core.Neo4jClient; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; + +import java.util.HashSet; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.when; + +@ActiveProfiles("test") +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@SpringBootTest +class UpdateProjectUseCaseTest { + + private Member testMember; + + @MockBean + private MemberUtils memberUtils; + @SpyBean + private ProjectNodeRepository projectNodeRepository; + + @Autowired + private CreateProjectUseCase createProjectUseCase; + @Autowired + private MemberRepository memberRepository; + @Autowired + private StoryFolderRepository storyFolderRepository; + @Autowired + private UniverseFolderRepository universeFolderRepository; + @Autowired + private ProjectRepository projectRepository; + @Autowired + private Neo4jClient neo4jClient; + @Autowired + private UpdateProjectUseCase updateProjectUseCase; + @Autowired + private ProjectAdapter projectAdapter; + + @DynamicPropertySource + static void loadProperties(DynamicPropertyRegistry registry) { + Dotenv dotenv = Dotenv.configure() + .directory("../") + .filename(".env") // .env 파일의 경로를 필요에 따라 지정 + .ignoreIfMissing() // .env 파일이 없으면 무시 + .load(); + + dotenv.entries().forEach(entry -> { + registry.add(entry.getKey(), entry.getValue()::toString); + }); + } + + @BeforeEach + void setUp() { + testMember = Member.builder() + .email("test@integration.com") + .password("integration1234") + .name("테스트유저") + .nickname("integUser") + .provider(OauthProvider.KAKAO) + .build(); + memberRepository.save(testMember); + + Mockito.reset(memberUtils, projectNodeRepository); + } + + @AfterEach + void tearDown() { + storyFolderRepository.deleteAllInBatch(); + universeFolderRepository.deleteAllInBatch(); + projectRepository.deleteAllInBatch(); + memberRepository.deleteAllInBatch(); + + if (neo4jClient == null) { + throw new IllegalStateException("Neo4jClient is null, cannot clean up Neo4j DB."); + } + neo4jClient.query("MATCH (n) DETACH DELETE n;").run(); + } + + @Test + @DisplayName("프로젝트 정보가 정상적으로 수정된다.") + void updateProjectSuccess() { + // given + when(memberUtils.getCurrentMemberReference()).thenReturn(testMember); + when(memberUtils.getCurrentMemberId()).thenReturn(testMember.getId()); + + ProjectShortInfoResponse created = createProjectUseCase.execute( + new AddProjectRequest( + "Original Title", + "Original Desc", + Category.ESSAY, + new HashSet<>(), + null + ) + ); + Long projectId = created.project().id(); + + UpdateProjectRequest request = new UpdateProjectRequest( + "Updated Title", + "Updated Desc", + Category.ESSAY, + new HashSet<>(), + null + ); + + // when + updateProjectUseCase.execute(projectId, request); + + // then + Project updatedProject = projectAdapter.findById(projectId); + assertThat(created.project().id()).isEqualTo(updatedProject.getId()); + assertThat(updatedProject.getProjectInfo().getTitle()).isEqualTo(request.title()); + assertThat(updatedProject.getProjectInfo().getDescription()).isEqualTo(request.description()); + } + + @Test + @DisplayName("유효하지 않은 사용자가 수정 요청 시 예외가 발생한다.") + void updateProjectIllegalAccess() { + // given + when(memberUtils.getCurrentMemberReference()).thenReturn(testMember); + ProjectShortInfoResponse created = createProjectUseCase.execute( + new AddProjectRequest( + "Title", + "Desc", + Category.ESSAY, + new HashSet<>(), + null + ) + ); + Long projectId = created.project().id(); + + UpdateProjectRequest updateReq = new UpdateProjectRequest( + "X","Y", + Category.ESSAY, + new HashSet<>(), + null + ); + + when(memberUtils.getCurrentMemberId()).thenReturn(0L); + // when, then + assertThatThrownBy(() -> updateProjectUseCase.execute(projectId, updateReq)) + .isInstanceOf(ProjectIllegalAccessException.class) + .hasMessage(ProjectErrorCode.ILLEGAL_ACCESS.getMessage()); + } +} \ No newline at end of file diff --git a/Owing-Domain/Owing-Node/src/main/java/com/owing/node/domains/project/adapter/ProjectNodeAdapter.java b/Owing-Domain/Owing-Node/src/main/java/com/owing/node/domains/project/adapter/ProjectNodeAdapter.java index 9625ad4e..4512d456 100644 --- a/Owing-Domain/Owing-Node/src/main/java/com/owing/node/domains/project/adapter/ProjectNodeAdapter.java +++ b/Owing-Domain/Owing-Node/src/main/java/com/owing/node/domains/project/adapter/ProjectNodeAdapter.java @@ -7,6 +7,8 @@ import com.owing.node.domains.project.repository.ProjectNodeRepository; import lombok.RequiredArgsConstructor; +import java.util.Optional; + @Adaptor @RequiredArgsConstructor public class ProjectNodeAdapter { @@ -14,7 +16,10 @@ public class ProjectNodeAdapter { private final ProjectNodeRepository projectNodeRepository; public ProjectNode findById(Long projectId) { - return projectNodeRepository.findById(projectId) - .orElseThrow(() -> ProjectNodeNotFoundException.of(ProjectNodeErrorCode.PROJECT_NODE_NOT_FOUND, "Project Node Id: %d".formatted(projectId))); + Optional projectNode = projectNodeRepository.findById(projectId); + if (projectNode.isEmpty() || projectNode.get().isDeleted()) { + throw ProjectNodeNotFoundException.of(ProjectNodeErrorCode.PROJECT_NODE_NOT_FOUND, "Project Node Id: %d".formatted(projectId)); + } + return projectNode.get(); } }