From cb38234348d30577a21dba054fd12d4872c5aaca Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Wed, 13 Nov 2024 19:30:13 +0900 Subject: [PATCH 1/8] =?UTF-8?q?#114=20[feat]=20:=20User=20API=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=EB=A5=BC=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../side/onetime/user/UserControllerTest.java | 221 ++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 src/test/java/side/onetime/user/UserControllerTest.java diff --git a/src/test/java/side/onetime/user/UserControllerTest.java b/src/test/java/side/onetime/user/UserControllerTest.java new file mode 100644 index 0000000..1a5c30b --- /dev/null +++ b/src/test/java/side/onetime/user/UserControllerTest.java @@ -0,0 +1,221 @@ +package side.onetime.user; + +import com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper; +import com.epages.restdocs.apispec.ResourceSnippetParameters; +import com.epages.restdocs.apispec.Schema; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.ResultActions; +import side.onetime.configuration.ControllerTestConfig; +import side.onetime.controller.UserController; +import side.onetime.dto.user.request.OnboardUserRequest; +import side.onetime.dto.user.request.UpdateUserProfileRequest; +import side.onetime.dto.user.response.GetUserProfileResponse; +import side.onetime.dto.user.response.OnboardUserResponse; +import side.onetime.service.UserService; +import side.onetime.util.JwtUtil; + +import static com.epages.restdocs.apispec.ResourceDocumentation.resource; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(UserController.class) +public class UserControllerTest extends ControllerTestConfig { + @MockBean + private UserService userService; + + @MockBean + private JwtUtil jwtUtil; + + @Test + @DisplayName("유저 온보딩을 진행한다.") + public void onboardUser() throws Exception { + // given + OnboardUserResponse response = new OnboardUserResponse("sampleAccessToken", "sampleRefreshToken"); + Mockito.when(userService.onboardUser(any(OnboardUserRequest.class))).thenReturn(response); + + OnboardUserRequest request = new OnboardUserRequest("sampleRegisterToken", "UserNickname"); + + String requestContent = new ObjectMapper().writeValueAsString(request); + + // when + ResultActions resultActions = this.mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/users/onboarding") + .content(requestContent) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + + // then + resultActions + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("201")) + .andExpect(jsonPath("$.message").value("유저 온보딩에 성공했습니다.")) + .andExpect(jsonPath("$.payload.access_token").value("sampleAccessToken")) + .andExpect(jsonPath("$.payload.refresh_token").value("sampleRefreshToken")) + + // docs + .andDo(MockMvcRestDocumentationWrapper.document("user/onboard", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("User API") + .description("유저 온보딩을 진행한다.") + .requestFields( + fieldWithPath("register_token").type(JsonFieldType.STRING).description("레지스터 토큰"), + fieldWithPath("nickname").type(JsonFieldType.STRING).description("유저 닉네임") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload").type(JsonFieldType.OBJECT).description("응답 데이터"), + fieldWithPath("payload.access_token").type(JsonFieldType.STRING).description("액세스 토큰"), + fieldWithPath("payload.refresh_token").type(JsonFieldType.STRING).description("리프레쉬 토큰") + ) + .requestSchema(Schema.schema("OnboardUserRequestSchema")) + .responseSchema(Schema.schema("OnboardUserResponseSchema")) + .build() + ) + )); + } + + @Test + @DisplayName("유저 정보를 조회한다.") + public void getUserProfile() throws Exception { + // given + String nickname = "UserNickname"; + String email = "user@example.com"; + GetUserProfileResponse response = new GetUserProfileResponse(nickname, email); + + Mockito.when(userService.getUserProfile(anyString())).thenReturn(response); + + // when + ResultActions resultActions = this.mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/users/profile") + .header(HttpHeaders.AUTHORIZATION, "Bearer sampleToken") + .accept(MediaType.APPLICATION_JSON)); + + // then + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("유저 정보 조회에 성공했습니다.")) + .andExpect(jsonPath("$.payload.nickname").value(nickname)) + .andExpect(jsonPath("$.payload.email").value(email)) + + // docs + .andDo(MockMvcRestDocumentationWrapper.document("user/get-profile", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("User API") + .description("유저 정보를 조회한다.") + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload").type(JsonFieldType.OBJECT).description("유저 정보 데이터"), + fieldWithPath("payload.nickname").type(JsonFieldType.STRING).description("유저 닉네임"), + fieldWithPath("payload.email").type(JsonFieldType.STRING).description("유저 이메일") + ) + .responseSchema(Schema.schema("GetUserProfileResponseSchema")) + .build() + ) + )); + } + + @Test + @DisplayName("유저 정보를 수정한다.") + public void updateUserProfile() throws Exception { + // given + UpdateUserProfileRequest request = new UpdateUserProfileRequest("NewNickname"); + + Mockito.doNothing().when(userService).updateUserProfile(anyString(), any(UpdateUserProfileRequest.class)); + + String requestContent = new ObjectMapper().writeValueAsString(request); + + // when + ResultActions resultActions = this.mockMvc.perform(RestDocumentationRequestBuilders.patch("/api/v1/users/profile/action-update") + .header(HttpHeaders.AUTHORIZATION, "Bearer sampleToken") + .contentType(MediaType.APPLICATION_JSON) + .content(requestContent) + .accept(MediaType.APPLICATION_JSON)); + + // then + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("유저 정보 수정에 성공했습니다.")) + + // docs + .andDo(MockMvcRestDocumentationWrapper.document("user/update-profile", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("User API") + .description("유저 정보를 수정한다.") + .requestFields( + fieldWithPath("nickname").type(JsonFieldType.STRING).description("수정할 닉네임") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지") + ) + .build() + ) + )); + } + + @Test + @DisplayName("유저가 서비스를 탈퇴한다.") + public void withdrawService() throws Exception { + // given + Mockito.doNothing().when(userService).withdrawService(anyString()); + + // when + ResultActions resultActions = this.mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/users/action-withdraw") + .header(HttpHeaders.AUTHORIZATION, "Bearer sampleToken") + .accept(MediaType.APPLICATION_JSON)); + + // then + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("유저 서비스 탈퇴에 성공했습니다.")) + + // docs + .andDo(MockMvcRestDocumentationWrapper.document("user/withdraw-service", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("User API") + .description("유저가 서비스를 탈퇴한다.") + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지") + ) + .build() + ) + )); + } +} From 278116c56a58cc9d9e4b520c2e5167f3008f77cd Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Wed, 13 Nov 2024 19:37:23 +0900 Subject: [PATCH 2/8] =?UTF-8?q?#114=20[feat]=20:=20Url=20API=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=EB=A5=BC=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../side/onetime/url/UrlControllerTest.java | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 src/test/java/side/onetime/url/UrlControllerTest.java diff --git a/src/test/java/side/onetime/url/UrlControllerTest.java b/src/test/java/side/onetime/url/UrlControllerTest.java new file mode 100644 index 0000000..2ef690c --- /dev/null +++ b/src/test/java/side/onetime/url/UrlControllerTest.java @@ -0,0 +1,146 @@ +package side.onetime.url; + +import com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper; +import com.epages.restdocs.apispec.ResourceSnippetParameters; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +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.restdocs.mockmvc.RestDocumentationRequestBuilders; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.ResultActions; +import side.onetime.configuration.ControllerTestConfig; +import side.onetime.controller.UrlController; +import side.onetime.dto.url.request.ConvertToOriginalUrlRequest; +import side.onetime.dto.url.request.ConvertToShortenUrlRequest; +import side.onetime.dto.url.response.ConvertToOriginalUrlResponse; +import side.onetime.dto.url.response.ConvertToShortenUrlResponse; +import side.onetime.repository.EventRepository; +import side.onetime.service.UrlService; +import side.onetime.util.JwtUtil; + +import java.util.UUID; + +import static com.epages.restdocs.apispec.ResourceDocumentation.resource; +import static org.mockito.ArgumentMatchers.any; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(UrlController.class) +public class UrlControllerTest extends ControllerTestConfig { + @MockBean + private UrlService urlService; + + @MockBean + private EventRepository eventRepository; + + @MockBean + private JwtUtil jwtUtil; + + @Test + @DisplayName("원본 URL을 단축 URL로 변환한다.") + public void convertToShortenUrl() throws Exception { + // given + String originalUrl = "https://example.com/event/123e4567-e89b-12d3-a456-426614174000"; + ConvertToShortenUrlRequest request = new ConvertToShortenUrlRequest(originalUrl); + String shortenUrl = "https://short.ly/abc123"; + + Mockito.when(eventRepository.existsByEventId(any(UUID.class))).thenReturn(true); + Mockito.when(urlService.convertToShortenUrl(any(ConvertToShortenUrlRequest.class))) + .thenReturn(ConvertToShortenUrlResponse.of(shortenUrl)); + + String requestContent = new ObjectMapper().writeValueAsString(request); + + // when + ResultActions resultActions = this.mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/urls/action-shorten") + .contentType(MediaType.APPLICATION_JSON) + .content(requestContent) + .accept(MediaType.APPLICATION_JSON)); + + // then + resultActions + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("201")) + .andExpect(jsonPath("$.message").value("단축 URL 변환에 성공했습니다.")) + .andExpect(jsonPath("$.payload.shorten_url").value(shortenUrl)) + + // docs + .andDo(MockMvcRestDocumentationWrapper.document("url/convert-to-shorten", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("URL API") + .description("원본 URL을 단축 URL로 변환한다.") + .requestFields( + fieldWithPath("original_url").type(JsonFieldType.STRING).description("단축할 원본 URL") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload").type(JsonFieldType.OBJECT).description("응답 데이터"), + fieldWithPath("payload.shorten_url").type(JsonFieldType.STRING).description("생성된 단축 URL") + ) + .build() + ) + )); + } + + @Test + @DisplayName("단축 URL을 원본 URL로 변환한다.") + public void convertToOriginalUrl() throws Exception { + // given + String shortenUrl = "https://short.ly/abc123"; + ConvertToOriginalUrlRequest request = new ConvertToOriginalUrlRequest(shortenUrl); + String originalUrl = "https://example.com/event/123e4567-e89b-12d3-a456-426614174000"; + + Mockito.when(urlService.convertToOriginalUrl(any(ConvertToOriginalUrlRequest.class))) + .thenReturn(ConvertToOriginalUrlResponse.of(originalUrl)); + Mockito.when(eventRepository.existsByEventId(any(UUID.class))).thenReturn(true); + + String requestContent = new ObjectMapper().writeValueAsString(request); + + // when + ResultActions resultActions = this.mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/urls/action-original") + .contentType(MediaType.APPLICATION_JSON) + .content(requestContent) + .accept(MediaType.APPLICATION_JSON)); + + // then + resultActions + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("201")) + .andExpect(jsonPath("$.message").value("원본 URL 변환에 성공했습니다.")) + .andExpect(jsonPath("$.payload.original_url").value(originalUrl)) + + // docs + .andDo(MockMvcRestDocumentationWrapper.document("url/convert-to-original", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("URL API") + .description("단축 URL을 원본 URL로 변환한다.") + .requestFields( + fieldWithPath("shorten_url").type(JsonFieldType.STRING).description("복원할 단축 URL") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload").type(JsonFieldType.OBJECT).description("응답 데이터"), + fieldWithPath("payload.original_url").type(JsonFieldType.STRING).description("복원된 원본 URL") + ) + .build() + ) + )); + } +} \ No newline at end of file From 61383deafa4f6cf8ba4d970173f87fe0d573ac97 Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Wed, 13 Nov 2024 19:40:59 +0900 Subject: [PATCH 3/8] =?UTF-8?q?#114=20[feat]=20:=20Token=20API=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=EB=A5=BC=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../onetime/token/TokenControllerTest.java | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/test/java/side/onetime/token/TokenControllerTest.java diff --git a/src/test/java/side/onetime/token/TokenControllerTest.java b/src/test/java/side/onetime/token/TokenControllerTest.java new file mode 100644 index 0000000..a16fe04 --- /dev/null +++ b/src/test/java/side/onetime/token/TokenControllerTest.java @@ -0,0 +1,91 @@ +package side.onetime.token; + +import com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper; +import com.epages.restdocs.apispec.ResourceSnippetParameters; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +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.restdocs.mockmvc.RestDocumentationRequestBuilders; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.ResultActions; +import side.onetime.configuration.ControllerTestConfig; +import side.onetime.controller.TokenController; +import side.onetime.dto.token.request.ReissueTokenRequest; +import side.onetime.dto.token.response.ReissueTokenResponse; +import side.onetime.service.TokenService; +import side.onetime.util.JwtUtil; + +import static com.epages.restdocs.apispec.ResourceDocumentation.resource; +import static org.mockito.ArgumentMatchers.any; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(TokenController.class) +public class TokenControllerTest extends ControllerTestConfig { + @MockBean + private TokenService tokenService; + + @MockBean + private JwtUtil jwtUtil; + + @Test + @DisplayName("액세스 토큰을 재발행한다.") + public void reissueTokenSuccess() throws Exception { + // given + String oldRefreshToken = "sampleOldRefreshToken"; + String newAccessToken = "newAccessToken"; + String newRefreshToken = "newRefreshToken"; + ReissueTokenResponse response = ReissueTokenResponse.of(newAccessToken, newRefreshToken); + + Mockito.when(tokenService.reissueToken(any(ReissueTokenRequest.class))) + .thenReturn(response); + + ReissueTokenRequest request = new ReissueTokenRequest(oldRefreshToken); + String requestContent = new ObjectMapper().writeValueAsString(request); + + // when + ResultActions resultActions = mockMvc.perform( + RestDocumentationRequestBuilders.post("/api/v1/tokens/action-reissue") + .content(requestContent) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + resultActions + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("201")) + .andExpect(jsonPath("$.message").value("토큰 재발행에 성공했습니다.")) + .andExpect(jsonPath("$.payload.access_token").value(newAccessToken)) + .andExpect(jsonPath("$.payload.refresh_token").value(newRefreshToken)) + + // docs + .andDo(MockMvcRestDocumentationWrapper.document("token/reissue", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Token API") + .description("액세스 토큰을 재발행한다.") + .requestFields( + fieldWithPath("refresh_token").type(JsonFieldType.STRING).description("기존 리프레쉬 토큰") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload.access_token").type(JsonFieldType.STRING).description("새로운 액세스 토큰"), + fieldWithPath("payload.refresh_token").type(JsonFieldType.STRING).description("새로운 리프레쉬 토큰") + ) + .build() + ) + )); + } +} \ No newline at end of file From 3008756248121eef9fb15f10525cf987bd9182da Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Wed, 13 Nov 2024 20:29:59 +0900 Subject: [PATCH 4/8] =?UTF-8?q?#114=20[style]=20:=20=EA=B3=B5=EB=B0=B1?= =?UTF-8?q?=EC=9D=84=20=EC=B6=94=EA=B0=80=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/side/onetime/global/common/status/SuccessStatus.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/side/onetime/global/common/status/SuccessStatus.java b/src/main/java/side/onetime/global/common/status/SuccessStatus.java index 9fefd12..c139209 100644 --- a/src/main/java/side/onetime/global/common/status/SuccessStatus.java +++ b/src/main/java/side/onetime/global/common/status/SuccessStatus.java @@ -30,7 +30,7 @@ public enum SuccessStatus implements BaseCode { _GET_MEMBER_DAY_SCHEDULES(HttpStatus.OK, "200", "개인(비로그인) 요일 스케줄 조회에 성공했습니다."), _GET_USER_DAY_SCHEDULES(HttpStatus.OK, "200", "개인(로그인) 요일 스케줄 조회에 성공했습니다."), _GET_ALL_DATE_SCHEDULES(HttpStatus.OK, "200", "전체 날짜 스케줄 조회에 성공했습니다."), - _GET_MEMBER_DATE_SCHEDULES(HttpStatus.OK, "200", "개인(비로그인)날짜 스케줄 조회에 성공했습니다."), + _GET_MEMBER_DATE_SCHEDULES(HttpStatus.OK, "200", "개인(비로그인) 날짜 스케줄 조회에 성공했습니다."), _GET_USER_DATE_SCHEDULES(HttpStatus.OK, "200", "개인(로그인) 날짜 스케줄 조회에 성공했습니다."), _GET_FILTERED_DAY_SCHEDULES(HttpStatus.OK, "200", "멤버 필터링 요일 스케줄 조회에 성공했습니다."), _GET_FILTERED_DATE_SCHEDULES(HttpStatus.OK, "200", "멤버 필터링 날짜 스케줄 조회에 성공했습니다."), From 4db2ad83382985c3b21a3b88abdc4dd17f259b6e Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Wed, 13 Nov 2024 20:30:15 +0900 Subject: [PATCH 5/8] =?UTF-8?q?#114=20[feat]=20:=20Swagger=20=EB=AC=B8?= =?UTF-8?q?=EC=84=9C=EB=A5=BC=20=EC=95=8C=ED=8C=8C=EB=B2=B3=20=EC=88=9C?= =?UTF-8?q?=EC=84=9C=EB=A1=9C=20=EC=A0=95=EB=A0=AC=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yaml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index f4b22cf..1f64809 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -89,4 +89,13 @@ jwt: expiration-time: ${REGISTER_TOKEN_EXPIRATION_TIME} scheduling: - cron: ${CRON} \ No newline at end of file + cron: ${CRON} + +springdoc: + swagger-ui: + path: /swagger-ui.html + tags-sorter: alpha + operations-sorter: alpha + api-docs: + path: /v3/api-docs + show-actuator: true \ No newline at end of file From 0a43ddee4aff354ff5d7fd7b26fbb66a3ff492fd Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Wed, 13 Nov 2024 20:30:33 +0900 Subject: [PATCH 6/8] =?UTF-8?q?#114=20[feat]=20:=20Schedule=20API=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=EB=A5=BC=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../schedule/ScheduleControllerTest.java | 542 ++++++++++++++++++ 1 file changed, 542 insertions(+) create mode 100644 src/test/java/side/onetime/schedule/ScheduleControllerTest.java diff --git a/src/test/java/side/onetime/schedule/ScheduleControllerTest.java b/src/test/java/side/onetime/schedule/ScheduleControllerTest.java new file mode 100644 index 0000000..465628d --- /dev/null +++ b/src/test/java/side/onetime/schedule/ScheduleControllerTest.java @@ -0,0 +1,542 @@ +package side.onetime.schedule; + +import com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper; +import com.epages.restdocs.apispec.ResourceSnippetParameters; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +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.restdocs.mockmvc.RestDocumentationRequestBuilders; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.ResultActions; +import side.onetime.configuration.ControllerTestConfig; +import side.onetime.controller.ScheduleController; +import side.onetime.dto.schedule.request.CreateDateScheduleRequest; +import side.onetime.dto.schedule.request.CreateDayScheduleRequest; +import side.onetime.dto.schedule.request.GetFilteredSchedulesRequest; +import side.onetime.dto.schedule.response.DateSchedule; +import side.onetime.dto.schedule.response.DaySchedule; +import side.onetime.dto.schedule.response.PerDateSchedulesResponse; +import side.onetime.dto.schedule.response.PerDaySchedulesResponse; +import side.onetime.service.ScheduleService; +import side.onetime.util.JwtUtil; + +import java.util.List; +import java.util.UUID; + +import static com.epages.restdocs.apispec.ResourceDocumentation.resource; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(ScheduleController.class) +public class ScheduleControllerTest extends ControllerTestConfig { + @MockBean + private ScheduleService scheduleService; + + @MockBean + private JwtUtil jwtUtil; + + @Test + @DisplayName("요일 스케줄을 등록한다. (토큰 유무에 따라 로그인/비로그인 구분)") + public void createDaySchedulesForAnonymousUser() throws Exception { + // given + String eventId = "123e4567-e89b-12d3-a456-426614174000"; + String memberId = "789e0123-e45b-67c8-d901-234567890abc"; + List daySchedules = List.of( + new DaySchedule("월", List.of("09:00", "10:00")) + ); + CreateDayScheduleRequest request = new CreateDayScheduleRequest(eventId, memberId, daySchedules); + String requestContent = new ObjectMapper().writeValueAsString(request); + + Mockito.doNothing().when(scheduleService).createDaySchedulesForAnonymousUser(any(CreateDayScheduleRequest.class)); + + // when + ResultActions resultActions = mockMvc.perform( + RestDocumentationRequestBuilders.post("/api/v1/schedules/day") + .content(requestContent) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + resultActions + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("201")) + .andExpect(jsonPath("$.message").value("요일 스케줄 등록에 성공했습니다.")) + + // docs + .andDo(MockMvcRestDocumentationWrapper.document("schedule/create-day-anonymous", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Schedule API") + .description("요일 스케줄을 등록한다. (비로그인의 경우에는 멤버 ID가 필수 값)") + .requestFields( + fieldWithPath("event_id").type(JsonFieldType.STRING).description("이벤트 ID"), + fieldWithPath("member_id").type(JsonFieldType.STRING).description("멤버 ID"), + fieldWithPath("schedules[].time_point").type(JsonFieldType.STRING).description("요일"), + fieldWithPath("schedules[].times[]").type(JsonFieldType.ARRAY).description("스케줄 시간 목록") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지") + ) + .build() + ) + )); + } + + @Test + @DisplayName("날짜 스케줄을 등록한다. (토큰 유무에 따라 로그인/비로그인 구분)") + public void createDateSchedulesForAuthenticatedUser() throws Exception { + // given + String eventId = "123e4567-e89b-12d3-a456-426614174000"; + String memberId = "789e0123-e45b-67c8-d901-234567890abc"; + List dateSchedules = List.of( + new DateSchedule("2024.12.01", List.of("09:00", "10:00")) + ); + CreateDateScheduleRequest request = new CreateDateScheduleRequest(eventId, memberId, dateSchedules); + String requestContent = new ObjectMapper().writeValueAsString(request); + + Mockito.doNothing().when(scheduleService).createDateSchedulesForAnonymousUser(any(CreateDateScheduleRequest.class)); + + // when + ResultActions resultActions = mockMvc.perform( + RestDocumentationRequestBuilders.post("/api/v1/schedules/date") + .content(requestContent) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + resultActions + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("201")) + .andExpect(jsonPath("$.message").value("날짜 스케줄 등록에 성공했습니다.")) + + // docs + .andDo(MockMvcRestDocumentationWrapper.document("schedule/create-date-authenticated", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Schedule API") + .description("날짜 스케줄을 등록한다. (비로그인의 경우에는 멤버 ID가 필수 값)") + .requestFields( + fieldWithPath("event_id").type(JsonFieldType.STRING).description("이벤트 ID"), + fieldWithPath("member_id").type(JsonFieldType.STRING).optional().description("멤버 ID (로그인 유저는 필요 없음)"), + fieldWithPath("schedules[].time_point").type(JsonFieldType.STRING).description("날짜"), + fieldWithPath("schedules[].times[]").type(JsonFieldType.ARRAY).description("스케줄 시간 목록") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지") + ) + .build() + ) + )); + } + + @Test + @DisplayName("이벤트에 대한 모든 요일 스케줄을 조회한다.") + public void getAllDaySchedules() throws Exception { + // given + String eventId = UUID.randomUUID().toString(); + List daySchedules = List.of(new DaySchedule("월", List.of("09:00", "10:00"))); + List responses = List.of(PerDaySchedulesResponse.of("Test Member", daySchedules)); + + Mockito.when(scheduleService.getAllDaySchedules(anyString())).thenReturn(responses); + + // when + ResultActions resultActions = mockMvc.perform( + RestDocumentationRequestBuilders.get("/api/v1/schedules/day/{event_id}", eventId) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("전체 요일 스케줄 조회에 성공했습니다.")) + + // docs + .andDo(MockMvcRestDocumentationWrapper.document("schedule/get-all-day-schedules", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Schedule API") + .description("이벤트에 대한 모든 요일 스케줄을 조회한다.") + .pathParameters( + parameterWithName("event_id").description("이벤트 ID [예시 : dd099816-2b09-4625-bf95-319672c25659]") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload[].name").type(JsonFieldType.STRING).description("멤버 이름"), + fieldWithPath("payload[].schedules[].time_point").type(JsonFieldType.STRING).description("요일"), + fieldWithPath("payload[].schedules[].times[]").type(JsonFieldType.ARRAY).description("스케줄 시간 목록") + ) + .build() + ) + )); + } + + @Test + @DisplayName("개인 요일 스케줄을 조회한다. (비로그인 유저)") + public void getMemberDaySchedules() throws Exception { + // given + String eventId = UUID.randomUUID().toString(); + String memberId = UUID.randomUUID().toString(); + List daySchedules = List.of(new DaySchedule("화", List.of("11:00", "12:00"))); + PerDaySchedulesResponse response = PerDaySchedulesResponse.of("Test Member", daySchedules); + + Mockito.when(scheduleService.getMemberDaySchedules(anyString(), anyString())).thenReturn(response); + + // when + ResultActions resultActions = mockMvc.perform( + RestDocumentationRequestBuilders.get("/api/v1/schedules/day/{event_id}/{member_id}", eventId, memberId) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("개인(비로그인) 요일 스케줄 조회에 성공했습니다.")) + + // docs + .andDo(MockMvcRestDocumentationWrapper.document("schedule/get-member-day-schedules", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Schedule API") + .description("개인 요일 스케줄을 조회한다. (비로그인 유저)") + .pathParameters( + parameterWithName("event_id").description("이벤트 ID [예시 : dd099816-2b09-4625-bf95-319672c25659]"), + parameterWithName("member_id").description("멤버 ID [예시 : 789e0123-e45b-67c8-d901-234567890abc]") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload.name").type(JsonFieldType.STRING).description("멤버 이름"), + fieldWithPath("payload.schedules[].time_point").type(JsonFieldType.STRING).description("요일"), + fieldWithPath("payload.schedules[].times[]").type(JsonFieldType.ARRAY).description("스케줄 시간 목록") + ) + .build() + ) + )); + } + + @Test + @DisplayName("개인 요일 스케줄을 조회한다. (로그인 유저)") + public void getUserDaySchedules() throws Exception { + // given + String eventId = UUID.randomUUID().toString(); + String authorizationHeader = "Bearer sampleAuthToken"; + List daySchedules = List.of(new DaySchedule("수", List.of("13:00", "14:00"))); + PerDaySchedulesResponse response = PerDaySchedulesResponse.of("Test User", daySchedules); + + Mockito.when(scheduleService.getUserDaySchedules(anyString(), anyString())).thenReturn(response); + + // when + ResultActions resultActions = mockMvc.perform( + RestDocumentationRequestBuilders.get("/api/v1/schedules/day/{event_id}/user", eventId) + .header("Authorization", authorizationHeader) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("개인(로그인) 요일 스케줄 조회에 성공했습니다.")) + + // docs + .andDo(MockMvcRestDocumentationWrapper.document("schedule/get-user-day-schedules", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Schedule API") + .description("개인 요일 스케줄을 조회한다. (로그인 유저)") + .pathParameters( + parameterWithName("event_id").description("이벤트 ID [예시 : dd099816-2b09-4625-bf95-319672c25659]") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload.name").type(JsonFieldType.STRING).description("사용자 이름"), + fieldWithPath("payload.schedules[].time_point").type(JsonFieldType.STRING).description("요일"), + fieldWithPath("payload.schedules[].times[]").type(JsonFieldType.ARRAY).description("스케줄 시간 목록") + ) + .build() + ) + )); + } + + @Test + @DisplayName("멤버 필터링 요일 스케줄을 조회한다.") + public void getFilteredDaySchedules() throws Exception { + // given + String eventId = UUID.randomUUID().toString(); + List names = List.of("Test Member"); + GetFilteredSchedulesRequest request = new GetFilteredSchedulesRequest(eventId, names); + List daySchedules = List.of(new DaySchedule("월", List.of("09:00", "10:00"))); + List responses = List.of(PerDaySchedulesResponse.of("Test Member", daySchedules)); + + Mockito.when(scheduleService.getFilteredDaySchedules(any(GetFilteredSchedulesRequest.class))).thenReturn(responses); + + // when + String requestContent = new ObjectMapper().writeValueAsString(request); + ResultActions resultActions = mockMvc.perform( + RestDocumentationRequestBuilders.get("/api/v1/schedules/day/action-filtering") + .content(requestContent) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("멤버 필터링 요일 스케줄 조회에 성공했습니다.")) + + // docs + .andDo(MockMvcRestDocumentationWrapper.document("schedule/get-filtered-day-schedules", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Schedule API") + .description("멤버 필터링 요일 스케줄을 조회한다.") + .requestFields( + fieldWithPath("event_id").type(JsonFieldType.STRING).description("이벤트 ID"), + fieldWithPath("names[]").type(JsonFieldType.ARRAY).description("조회할 멤버 이름 목록") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload[].name").type(JsonFieldType.STRING).description("멤버 이름"), + fieldWithPath("payload[].schedules[].time_point").type(JsonFieldType.STRING).description("요일"), + fieldWithPath("payload[].schedules[].times[]").type(JsonFieldType.ARRAY).description("스케줄 시간 목록") + ) + .build() + ) + )); + } + + @Test + @DisplayName("이벤트에 대한 모든 날짜 스케줄을 조회한다.") + public void getAllDateSchedules() throws Exception { + // given + String eventId = UUID.randomUUID().toString(); + List dateSchedules = List.of(new DateSchedule("2024-12-01", List.of("09:00", "10:00"))); + List responses = List.of(PerDateSchedulesResponse.of("Test Member", dateSchedules)); + + Mockito.when(scheduleService.getAllDateSchedules(any(String.class))).thenReturn(responses); + + // when + ResultActions resultActions = mockMvc.perform( + RestDocumentationRequestBuilders.get("/api/v1/schedules/date/{event_id}", eventId) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("전체 날짜 스케줄 조회에 성공했습니다.")) + + // docs + .andDo(MockMvcRestDocumentationWrapper.document("schedule/get-all-date-schedules", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Schedule API") + .description("이벤트에 대한 모든 날짜 스케줄을 조회한다.") + .pathParameters( + parameterWithName("event_id").description("이벤트 ID [예시 : dd099816-2b09-4625-bf95-319672c25659]") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload[].name").type(JsonFieldType.STRING).description("멤버 이름"), + fieldWithPath("payload[].schedules[].time_point").type(JsonFieldType.STRING).description("날짜"), + fieldWithPath("payload[].schedules[].times[]").type(JsonFieldType.ARRAY).description("스케줄 시간 목록") + ) + .build() + ) + )); + } + + @Test + @DisplayName("개인 날짜 스케줄을 조회한다. (비로그인 유저)") + public void getMemberDateSchedules() throws Exception { + // given + String eventId = "123e4567-e89b-12d3-a456-426614174000"; + String memberId = "789e0123-e45b-67c8-d901-234567890abc"; + PerDateSchedulesResponse response = PerDateSchedulesResponse.of("memberName", List.of(new DateSchedule("2024.12.01", List.of("09:00", "10:00")))); + + Mockito.when(scheduleService.getMemberDateSchedules(eventId, memberId)).thenReturn(response); + + // when + ResultActions resultActions = mockMvc.perform( + RestDocumentationRequestBuilders.get("/api/v1/schedules/date/{event_id}/{member_id}", eventId, memberId) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("개인(비로그인) 날짜 스케줄 조회에 성공했습니다.")) + .andDo(MockMvcRestDocumentationWrapper.document("schedule/get-member-date", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Schedule API") + .description("개인 날짜 스케줄을 조회한다. (비로그인 유저)") + .pathParameters( + parameterWithName("event_id").description("이벤트 ID [예시 : dd099816-2b09-4625-bf95-319672c25659]"), + parameterWithName("member_id").description("멤버 ID [예시 : 789e0123-e45b-67c8-d901-234567890abc]") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload.name").type(JsonFieldType.STRING).description("멤버 이름"), + fieldWithPath("payload.schedules[].time_point").type(JsonFieldType.STRING).description("날짜"), + fieldWithPath("payload.schedules[].times[]").type(JsonFieldType.ARRAY).description("스케줄 시간 목록") + ) + .build() + ) + )); + } + + @Test + @DisplayName("개인 날짜 스케줄을 조회한다. (로그인 유저)") + public void getUserDateSchedules() throws Exception { + // given + String eventId = "123e4567-e89b-12d3-a456-426614174000"; + String authorizationHeader = "Bearer some_token"; + PerDateSchedulesResponse response = PerDateSchedulesResponse.of("userNickname", List.of(new DateSchedule("2024.12.01", List.of("09:00", "10:00")))); + + Mockito.when(scheduleService.getUserDateSchedules(eventId, authorizationHeader)).thenReturn(response); + + // when + ResultActions resultActions = mockMvc.perform( + RestDocumentationRequestBuilders.get("/api/v1/schedules/date/{event_id}/user", eventId) + .header("Authorization", authorizationHeader) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("개인(로그인) 날짜 스케줄 조회에 성공했습니다.")) + .andDo(MockMvcRestDocumentationWrapper.document("schedule/get-user-date", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Schedule API") + .description("개인 날짜 스케줄을 조회한다. (로그인 유저)") + .pathParameters( + parameterWithName("event_id").description("이벤트 ID [예시 : dd099816-2b09-4625-bf95-319672c25659]") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload.name").type(JsonFieldType.STRING).description("유저 닉네임"), + fieldWithPath("payload.schedules[].time_point").type(JsonFieldType.STRING).description("날짜"), + fieldWithPath("payload.schedules[].times[]").type(JsonFieldType.ARRAY).description("스케줄 시간 목록") + ) + .build() + ) + )); + } + + @Test + @DisplayName("멤버 필터링 날짜 스케줄을 조회한다.") + public void getFilteredDateSchedules() throws Exception { + // given + String eventId = "123e4567-e89b-12d3-a456-426614174000"; + List names = List.of("memberName1", "memberName2"); + GetFilteredSchedulesRequest request = new GetFilteredSchedulesRequest(eventId, names); + List responseList = List.of( + PerDateSchedulesResponse.of("memberName1", List.of(new DateSchedule("2024.12.01", List.of("09:00", "10:00")))), + PerDateSchedulesResponse.of("memberName2", List.of(new DateSchedule("2024.12.02", List.of("11:00", "12:00")))) + ); + + Mockito.when(scheduleService.getFilteredDateSchedules(any(GetFilteredSchedulesRequest.class))).thenReturn(responseList); + String requestContent = new ObjectMapper().writeValueAsString(request); + + // when + ResultActions resultActions = mockMvc.perform( + RestDocumentationRequestBuilders.get("/api/v1/schedules/date/action-filtering") + .content(requestContent) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("멤버 필터링 날짜 스케줄 조회에 성공했습니다.")) + .andDo(MockMvcRestDocumentationWrapper.document("schedule/get-filtered-date", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Schedule API") + .description("멤버 필터링 날짜 스케줄을 조회한다.") + .requestFields( + fieldWithPath("event_id").type(JsonFieldType.STRING).description("이벤트 ID"), + fieldWithPath("names[]").type(JsonFieldType.ARRAY).description("이름 목록") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload[].name").type(JsonFieldType.STRING).description("멤버 이름"), + fieldWithPath("payload[].schedules[].time_point").type(JsonFieldType.STRING).description("날짜"), + fieldWithPath("payload[].schedules[].times[]").type(JsonFieldType.ARRAY).description("스케줄 시간 목록") + ) + .build() + ) + )); + } +} \ No newline at end of file From f7b82f249f2dbdc3f970691032c6264ed04cbfa0 Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Wed, 13 Nov 2024 20:46:02 +0900 Subject: [PATCH 7/8] =?UTF-8?q?#114=20[feat]=20:=20Member=20API=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=EB=A5=BC=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../onetime/member/MemberControllerTest.java | 201 ++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 src/test/java/side/onetime/member/MemberControllerTest.java diff --git a/src/test/java/side/onetime/member/MemberControllerTest.java b/src/test/java/side/onetime/member/MemberControllerTest.java new file mode 100644 index 0000000..307bcfd --- /dev/null +++ b/src/test/java/side/onetime/member/MemberControllerTest.java @@ -0,0 +1,201 @@ +package side.onetime.member; + +import com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper; +import com.epages.restdocs.apispec.ResourceSnippetParameters; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +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.restdocs.mockmvc.RestDocumentationRequestBuilders; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.ResultActions; +import side.onetime.configuration.ControllerTestConfig; +import side.onetime.controller.MemberController; +import side.onetime.domain.enums.Category; +import side.onetime.dto.member.request.IsDuplicateRequest; +import side.onetime.dto.member.request.LoginMemberRequest; +import side.onetime.dto.member.request.RegisterMemberRequest; +import side.onetime.dto.member.response.IsDuplicateResponse; +import side.onetime.dto.member.response.LoginMemberResponse; +import side.onetime.dto.member.response.RegisterMemberResponse; +import side.onetime.dto.member.response.ScheduleResponse; +import side.onetime.service.MemberService; +import side.onetime.util.JwtUtil; + +import java.util.List; + +import static com.epages.restdocs.apispec.ResourceDocumentation.resource; +import static org.mockito.ArgumentMatchers.any; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(MemberController.class) +public class MemberControllerTest extends ControllerTestConfig { + + @MockBean + private MemberService memberService; + + @MockBean + private JwtUtil jwtUtil; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + @DisplayName("멤버를 등록한다.") + public void registerMember() throws Exception { + // given + RegisterMemberRequest request = new RegisterMemberRequest( + "123e4567-e89b-12d3-a456-426614174000", + "newMember", + "1234", + List.of( + new ScheduleResponse("2024.12.01", List.of("09:00", "10:00")), + new ScheduleResponse("2024.12.02", List.of("11:00", "12:00")) + ) + ); + RegisterMemberResponse response = new RegisterMemberResponse("789e0123-e45b-67c8-d901-234567890abc", "CATEGORY"); + + Mockito.when(memberService.registerMember(any(RegisterMemberRequest.class))).thenReturn(response); + + // when + ResultActions result = mockMvc.perform( + RestDocumentationRequestBuilders.post("/api/v1/members/action-register") + .content(objectMapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + result.andExpect(status().isCreated()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("201")) + .andExpect(jsonPath("$.message").value("멤버 등록에 성공했습니다.")) + .andDo(MockMvcRestDocumentationWrapper.document("member/register", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Member API") + .description("멤버를 등록한다.") + .requestFields( + fieldWithPath("event_id").type(JsonFieldType.STRING).description("이벤트 ID"), + fieldWithPath("name").type(JsonFieldType.STRING).description("멤버 이름"), + fieldWithPath("pin").type(JsonFieldType.STRING).description("멤버 PIN"), + fieldWithPath("schedules").type(JsonFieldType.ARRAY).description("스케줄 목록"), + fieldWithPath("schedules[].time_point").type(JsonFieldType.STRING).description("스케줄 날짜"), + fieldWithPath("schedules[].times").type(JsonFieldType.ARRAY).description("시간 목록") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("HTTP 상태 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload.member_id").type(JsonFieldType.STRING).description("멤버 ID"), + fieldWithPath("payload.category").type(JsonFieldType.STRING).description("이벤트 카테고리") + ) + .build() + ) + )); + } + + @Test + @DisplayName("멤버 로그인을 진행한다.") + public void loginMember() throws Exception { + // given + LoginMemberRequest request = new LoginMemberRequest( + "123e4567-e89b-12d3-a456-426614174000", + "existingMember", + "1234" + ); + LoginMemberResponse response = new LoginMemberResponse("789e0123-e45b-67c8-d901-234567890abc", "DATE"); + + Mockito.when(memberService.loginMember(any(LoginMemberRequest.class))).thenReturn(response); + + // when + ResultActions result = mockMvc.perform( + RestDocumentationRequestBuilders.post("/api/v1/members/action-login") + .content(objectMapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + result.andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("멤버 로그인에 성공했습니다.")) + .andDo(MockMvcRestDocumentationWrapper.document("member/login", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Member API") + .description("멤버 로그인을 진행한다.") + .requestFields( + fieldWithPath("event_id").type(JsonFieldType.STRING).description("이벤트 ID"), + fieldWithPath("name").type(JsonFieldType.STRING).description("멤버 이름"), + fieldWithPath("pin").type(JsonFieldType.STRING).description("멤버 PIN") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("HTTP 상태 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload.member_id").type(JsonFieldType.STRING).description("멤버 ID"), + fieldWithPath("payload.category").type(JsonFieldType.STRING).description("이벤트 카테고리") + ) + .build() + ) + )); + } + + @Test + @DisplayName("멤버 이름 중복 확인을 진행한다.") + public void isDuplicate() throws Exception { + // given + IsDuplicateRequest request = new IsDuplicateRequest( + "123e4567-e89b-12d3-a456-426614174000", + "duplicateCheckName" + ); + IsDuplicateResponse response = new IsDuplicateResponse(true); + + Mockito.when(memberService.isDuplicate(any(IsDuplicateRequest.class))).thenReturn(response); + + // when + ResultActions result = mockMvc.perform( + RestDocumentationRequestBuilders.post("/api/v1/members/name/action-check") + .content(objectMapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + result.andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("멤버 이름 중복 확인에 성공했습니다.")) + .andDo(MockMvcRestDocumentationWrapper.document("member/check-duplicate", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Member API") + .description("멤버 이름 중복 확인을 진행한다.") + .requestFields( + fieldWithPath("event_id").type(JsonFieldType.STRING).description("이벤트 ID"), + fieldWithPath("name").type(JsonFieldType.STRING).description("확인할 멤버 이름") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("HTTP 상태 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload.is_possible").type(JsonFieldType.BOOLEAN).description("이름 사용 가능 여부") + ) + .build() + ) + )); + } +} \ No newline at end of file From 44a3fdf5ce6772561e868fbd967bbe0dcedf6513 Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Wed, 13 Nov 2024 21:47:27 +0900 Subject: [PATCH 8/8] =?UTF-8?q?#114=20[feat]=20:=20Fixed=20API=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=EB=A5=BC=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../onetime/fixed/FixedControllerTest.java | 309 ++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 src/test/java/side/onetime/fixed/FixedControllerTest.java diff --git a/src/test/java/side/onetime/fixed/FixedControllerTest.java b/src/test/java/side/onetime/fixed/FixedControllerTest.java new file mode 100644 index 0000000..9f50398 --- /dev/null +++ b/src/test/java/side/onetime/fixed/FixedControllerTest.java @@ -0,0 +1,309 @@ +package side.onetime.fixed; + +import com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper; +import com.epages.restdocs.apispec.ResourceSnippetParameters; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +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.restdocs.mockmvc.RestDocumentationRequestBuilders; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.ResultActions; +import side.onetime.configuration.ControllerTestConfig; +import side.onetime.controller.FixedController; +import side.onetime.dto.fixed.request.CreateFixedEventRequest; +import side.onetime.dto.fixed.request.ModifyFixedEventRequest; +import side.onetime.dto.fixed.response.FixedEventByDayResponse; +import side.onetime.dto.fixed.response.FixedEventDetailResponse; +import side.onetime.dto.fixed.response.FixedEventResponse; +import side.onetime.dto.fixed.response.FixedScheduleResponse; +import side.onetime.service.FixedEventService; +import side.onetime.service.FixedScheduleService; +import side.onetime.util.JwtUtil; + +import java.util.List; + +import static com.epages.restdocs.apispec.ResourceDocumentation.resource; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(FixedController.class) +public class FixedControllerTest extends ControllerTestConfig { + + @MockBean + private FixedEventService fixedEventService; + + @MockBean + private FixedScheduleService fixedScheduleService; + + @MockBean + private JwtUtil jwtUtil; + + private final String authorizationHeader = "Bearer token"; + + @Test + @DisplayName("고정 스케줄을 등록한다.") + public void createFixedEvent() throws Exception { + // given + CreateFixedEventRequest request = new CreateFixedEventRequest("고정 이벤트", List.of(new FixedScheduleResponse("월", List.of("09:00", "09:30")))); + + // when + ResultActions result = mockMvc.perform( + RestDocumentationRequestBuilders.post("/api/v1/fixed-schedules") + .header("Authorization", authorizationHeader) + .content(objectMapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + result.andExpect(status().isCreated()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("201")) + .andExpect(jsonPath("$.message").value("고정 스케줄 등록에 성공했습니다.")) + .andDo(MockMvcRestDocumentationWrapper.document("fixed/create", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Fixed API") + .description("고정 스케줄을 등록한다.") + .requestFields( + fieldWithPath("title").type(JsonFieldType.STRING).description("스케줄 이름"), + fieldWithPath("schedules").type(JsonFieldType.ARRAY).description("고정 스케줄 목록"), + fieldWithPath("schedules[].time_point").type(JsonFieldType.STRING).description("요일"), + fieldWithPath("schedules[].times").type(JsonFieldType.ARRAY).description("시간 목록") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("HTTP 상태 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지") + ) + .build() + ) + )); + } + + @Test + @DisplayName("전체 고정 스케줄을 조회한다.") + public void getAllFixedSchedules() throws Exception { + // given + List responses = List.of( + new FixedEventResponse(1L, "09:00", "10:00", List.of(new FixedScheduleResponse("월", List.of("09:00", "09:30")))), + new FixedEventResponse(2L, "09:00", "10:00", List.of(new FixedScheduleResponse("화", List.of("09:00", "09:30")))) + ); + Mockito.when(fixedScheduleService.getAllFixedSchedules(authorizationHeader)).thenReturn(responses); + + // when + ResultActions result = mockMvc.perform( + RestDocumentationRequestBuilders.get("/api/v1/fixed-schedules") + .header("Authorization", authorizationHeader) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + result.andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("전체 고정 스케줄 조회에 성공했습니다.")) + .andDo(MockMvcRestDocumentationWrapper.document("fixed/getAll", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Fixed API") + .description("전체 고정 스케줄을 조회한다.") + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("HTTP 상태 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload[].id").type(JsonFieldType.NUMBER).description("고정 스케줄 ID"), + fieldWithPath("payload[].start_time").type(JsonFieldType.STRING).description("시작 시간"), + fieldWithPath("payload[].end_time").type(JsonFieldType.STRING).description("종료 시간"), + fieldWithPath("payload[].schedules[].time_point").type(JsonFieldType.STRING).description("요일"), + fieldWithPath("payload[].schedules[].times[]").type(JsonFieldType.ARRAY).description("시간 목록") + ) + .build() + ) + )); + } + + @Test + @DisplayName("특정 고정 스케줄을 상세 조회한다.") + public void getFixedScheduleDetail() throws Exception { + // given + Long fixedEventId = 1L; + FixedEventDetailResponse response = new FixedEventDetailResponse("고정 이벤트", "09:00", "10:00", List.of(new FixedScheduleResponse("월", List.of("09:00", "09:30")))); + Mockito.when(fixedScheduleService.getFixedScheduleDetail(authorizationHeader, fixedEventId)).thenReturn(response); + + // when + ResultActions result = mockMvc.perform( + RestDocumentationRequestBuilders.get("/api/v1/fixed-schedules/{id}", fixedEventId) + .header("Authorization", authorizationHeader) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + result.andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("특정 고정 스케줄 상세 조회에 성공했습니다.")) + .andDo(MockMvcRestDocumentationWrapper.document("fixed/getDetail", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Fixed API") + .description("특정 고정 스케줄을 상세 조회한다.") + .pathParameters( + parameterWithName("id").description("고정 스케줄 ID [예시 : 1 (NUMBER Type)]") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("HTTP 상태 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload.title").type(JsonFieldType.STRING).description("고정 스케줄 제목"), + fieldWithPath("payload.start_time").type(JsonFieldType.STRING).description("시작 시간"), + fieldWithPath("payload.end_time").type(JsonFieldType.STRING).description("종료 시간"), + fieldWithPath("payload.schedules[].time_point").type(JsonFieldType.STRING).description("요일"), + fieldWithPath("payload.schedules[].times[]").type(JsonFieldType.ARRAY).description("시간 목록") + ) + .build() + ) + )); + } + + @Test + @DisplayName("특정 고정 스케줄을 수정한다.") + public void modifyFixedEvent() throws Exception { + // given + Long fixedEventId = 1L; + ModifyFixedEventRequest request = new ModifyFixedEventRequest("수정된 고정 스케줄", List.of(new FixedScheduleResponse("화", List.of("10:00", "11:00")))); + + // when + ResultActions result = mockMvc.perform( + RestDocumentationRequestBuilders.patch("/api/v1/fixed-schedules/{id}", fixedEventId) + .header("Authorization", authorizationHeader) + .content(objectMapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + result.andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("고정 스케줄 수정에 성공했습니다.")) + .andDo(MockMvcRestDocumentationWrapper.document("fixed/modify", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Fixed API") + .description("특정 고정 스케줄을 수정한다.") + .pathParameters( + parameterWithName("id").description("고정 스케줄 ID [예시 : 1 (NUMBER Type)]") + ) + .requestFields( + fieldWithPath("title").type(JsonFieldType.STRING).description("수정된 스케줄 이름"), + fieldWithPath("schedules").type(JsonFieldType.ARRAY).description("수정된 고정 스케줄 목록"), + fieldWithPath("schedules[].time_point").type(JsonFieldType.STRING).description("요일"), + fieldWithPath("schedules[].times").type(JsonFieldType.ARRAY).description("시간 목록") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("HTTP 상태 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지") + ) + .build() + ) + )); + } + + @Test + @DisplayName("특정 고정 스케줄을 삭제한다.") + public void removeFixedEvent() throws Exception { + // given + Long fixedEventId = 1L; + + // when + ResultActions result = mockMvc.perform( + RestDocumentationRequestBuilders.delete("/api/v1/fixed-schedules/{id}", fixedEventId) + .header("Authorization", authorizationHeader) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + result.andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("고정 스케줄 삭제에 성공했습니다.")) + .andDo(MockMvcRestDocumentationWrapper.document("fixed/delete", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Fixed API") + .description("특정 고정 스케줄을 삭제한다.") + .pathParameters( + parameterWithName("id").description("고정 스케줄 ID [예시 : 1 (NUMBER Type)]") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("HTTP 상태 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지") + ) + .build() + ) + )); + } + + @Test + @DisplayName("요일별 고정 스케줄을 조회한다.") + public void getFixedEventByDay() throws Exception { + // given + String day = "mon"; + List responses = List.of(new FixedEventByDayResponse(1L, "고정 이벤트", "09:00", "10:00")); + Mockito.when(fixedEventService.getFixedEventByDay(authorizationHeader, day)).thenReturn(responses); + + // when + ResultActions result = mockMvc.perform( + RestDocumentationRequestBuilders.get("/api/v1/fixed-schedules/by-day/{day}", day) + .header("Authorization", authorizationHeader) + .accept(MediaType.APPLICATION_JSON) + ); + + // then + result.andExpect(status().isOk()) + .andExpect(jsonPath("$.is_success").value(true)) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.message").value("요일 별 고정 스케줄 조회에 성공했습니다.")) + .andDo(MockMvcRestDocumentationWrapper.document("fixed/getByDay", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Fixed API") + .description("요일별 고정 스케줄을 조회한다.") + .pathParameters( + parameterWithName("day").description("조회할 요일 [예시 : mon, tue, ...]") + ) + .responseFields( + fieldWithPath("is_success").type(JsonFieldType.BOOLEAN).description("성공 여부"), + fieldWithPath("code").type(JsonFieldType.STRING).description("HTTP 상태 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("payload[].id").type(JsonFieldType.NUMBER).description("고정 스케줄 ID"), + fieldWithPath("payload[].title").type(JsonFieldType.STRING).description("고정 스케줄 이름"), + fieldWithPath("payload[].start_time").type(JsonFieldType.STRING).description("시작 시간"), + fieldWithPath("payload[].end_time").type(JsonFieldType.STRING).description("종료 시간") + ) + .build() + ) + )); + } +} \ No newline at end of file