From d32e7cf4423635d1a6cc4bae43eb09d5aa5fe434 Mon Sep 17 00:00:00 2001 From: hellomatia Date: Tue, 21 May 2024 15:02:21 +0900 Subject: [PATCH 01/11] =?UTF-8?q?feat:=20spring=20docs=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/build.gradle b/build.gradle index f5f09bf..afd4dab 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,6 @@ plugins { id 'java' + id "org.asciidoctor.jvm.convert" version "3.3.2" id 'org.springframework.boot' version '3.2.5' id 'io.spring.dependency-management' version '1.1.4' } @@ -12,6 +13,7 @@ java { } configurations { + asciidoctorExt compileOnly { extendsFrom annotationProcessor } @@ -49,6 +51,9 @@ dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' implementation group: 'org.javassist', name: 'javassist', version: '3.15.0-GA' + + asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor' + testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' } tasks.named('test') { @@ -76,4 +81,18 @@ bootRun { String activeProfile = System.properties['spring.profiles.active'] println "zone: $activeProfile" systemProperty "spring.profiles.active", activeProfile +} + +ext { + snippetsDir = file('build/generated-snippets') +} + +test { + outputs.dir snippetsDir +} + +asciidoctor { + inputs.dir snippetsDir + configurations 'asciidoctorExt' + dependsOn test } \ No newline at end of file From b55a30826729f3ffecf32f598e96e87d0f314f68 Mon Sep 17 00:00:00 2001 From: hellomatia Date: Tue, 21 May 2024 16:12:44 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feat:=20api=20docs=20html=20=EB=AC=B8?= =?UTF-8?q?=EC=84=9C=20=EC=83=9D=EC=84=B1=20=ED=99=98=EA=B2=BD=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index afd4dab..5427e80 100644 --- a/build.gradle +++ b/build.gradle @@ -95,4 +95,22 @@ asciidoctor { inputs.dir snippetsDir configurations 'asciidoctorExt' dependsOn test -} \ No newline at end of file +} + +bootJar { + dependsOn asciidoctor + from ("${asciidoctor.outputDir}/html5") { + into 'static/docs' + } +} + +tasks.register('copyDocument', Copy) { + dependsOn asciidoctor + + from file("build/docs/asciidoc/") + into file("src/main/resources/static/docs") +} + +build { + dependsOn copyDocument +} From 75b2a85b6ca5327a065acf63dd79135fe54ff59b Mon Sep 17 00:00:00 2001 From: hellomatia Date: Tue, 21 May 2024 17:30:30 +0900 Subject: [PATCH 03/11] =?UTF-8?q?fix:=20=ED=9A=8C=EC=9B=90=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EC=8B=9C=20=EB=B9=84=EC=96=B4=EC=9E=88=EB=8A=94=20?= =?UTF-8?q?=EA=B0=92=EC=9D=B4=20=EC=9E=88=EC=9C=BC=EB=A9=B4,=20=EA=B8=B0?= =?UTF-8?q?=EC=A1=B4=20=EA=B0=92=EC=9C=BC=EB=A1=9C=20=EB=8C=80=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/mlog/user/service/UserService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/mlog/user/service/UserService.java b/src/main/java/com/mlog/user/service/UserService.java index e363490..5f2c8b7 100644 --- a/src/main/java/com/mlog/user/service/UserService.java +++ b/src/main/java/com/mlog/user/service/UserService.java @@ -72,9 +72,9 @@ public boolean update(UserDTO userDTO, Long id) { User data = userMapper.findById(id).orElseThrow(() -> new UnauthorizedException("Invalid id")); userMapper.update(User.builder() .id(id) - .name(userDTO.getName() != null ? userDTO.getName() : null) - .email(userDTO.getEmail()) - .password(passwordEncoder.encode(userDTO.getPassword())) + .name(userDTO.getName() != null ? userDTO.getName() : data.getName()) + .email(userDTO.getEmail() != null ? userDTO.getEmail() : data.getEmail()) + .password(userDTO.getPassword() != null ? passwordEncoder.encode(userDTO.getPassword()) : data.getPassword()) .role("ROLE_USER") .build()); From 91cd58d1be705afec3edc6161407be249282547e Mon Sep 17 00:00:00 2001 From: hellomatia Date: Tue, 21 May 2024 17:31:13 +0900 Subject: [PATCH 04/11] =?UTF-8?q?refactor:=20=EC=98=88=EC=8B=9C=20?= =?UTF-8?q?=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/mlog/user/controller/UserController.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/com/mlog/user/controller/UserController.java b/src/main/java/com/mlog/user/controller/UserController.java index 1bdab99..e8b7998 100644 --- a/src/main/java/com/mlog/user/controller/UserController.java +++ b/src/main/java/com/mlog/user/controller/UserController.java @@ -32,11 +32,6 @@ public class UserController { private final AuthenticationManager authenticationManager; private final UserService userService; - @GetMapping - public ApiResult hello() { - return success("hello user"); - } - @PostMapping("/login") public ApiResult login(@Valid @RequestBody LoginRequest request) throws UnauthorizedException { From c7de8d354911ab52705c9a46e56b420c3e620460 Mon Sep 17 00:00:00 2001 From: hellomatia Date: Tue, 21 May 2024 17:46:29 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20UserControllerTest=20RestDocs=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserControllerTest.java | 542 +++++++++--------- 1 file changed, 275 insertions(+), 267 deletions(-) diff --git a/src/test/java/com/mlog/user/controller/UserControllerTest.java b/src/test/java/com/mlog/user/controller/UserControllerTest.java index a2d8a71..182ca8d 100644 --- a/src/test/java/com/mlog/user/controller/UserControllerTest.java +++ b/src/test/java/com/mlog/user/controller/UserControllerTest.java @@ -1,289 +1,297 @@ package com.mlog.user.controller; -import org.json.JSONObject; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.RestDocumentationExtension; import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; -import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.is; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; +@ExtendWith({SpringExtension.class, RestDocumentationExtension.class}) @SpringBootTest +@AutoConfigureRestDocs @AutoConfigureMockMvc class UserControllerTest { -// -// @Autowired -// private MockMvc mockMvc; -// -// @Test -// public void user_테스트_예시() throws Exception { -// -// MvcResult result = mockMvc.perform(get("/user") -// .contentType(MediaType.APPLICATION_JSON)) -// .andExpect(status().isOk()) -// .andReturn(); -// -// JSONObject response = new JSONObject(result.getResponse().getContentAsString()); -// assertThat(response.get("success")) -// .isEqualTo(true); -// assertThat("hello user") -// .isEqualTo(response.get("response")); -// assertThat(response.get("error")) -// .isEqualTo(null); -// } -// -// @Test -// public void 올바른_이메일_AND_비밀번호로_로그인할_경우_성공() throws Exception { -// ResultActions result = mockMvc.perform(post("/user/login") -// .contentType(MediaType.APPLICATION_JSON) -// .accept(MediaType.APPLICATION_JSON) -// .content("{\"principal\":\"tester@gmail.com\",\"credentials\":\"1234\"}") -// ); -// -// result.andDo(print()) -// .andExpect(status().isOk()) -// .andExpect(handler().handlerType(UserController.class)) -// .andExpect(handler().methodName("login")) -// .andExpect(jsonPath("$.success", is(true))) -// .andExpect(jsonPath("$.response.token").exists()) -// .andExpect(jsonPath("$.response.token").isString()) -// .andExpect(jsonPath("$.response.user.name", is("tester"))) -// .andExpect(jsonPath("$.response.user.email", is("tester@gmail.com"))) -// .andExpect(jsonPath("$.response.user.createdAt").exists()) -// .andExpect(jsonPath("$.response.user.updatedAt").exists()) -// ; -// } -// -// @Test -// public void 올바르지_않은_이메일_올바른_비밀번호로_로그인할_경우_실패() throws Exception { -// ResultActions result = mockMvc.perform(post("/user/login") -// .contentType(MediaType.APPLICATION_JSON) -// .accept(MediaType.APPLICATION_JSON) -// .content("{\"principal\":\"wrong@gmail.com\",\"credentials\":\"1234\"}") -// ); -// -// result.andDo(print()) -// .andExpect(status().is4xxClientError()) -// .andExpect(handler().handlerType(UserController.class)) -// .andExpect(handler().methodName("login")) -// .andExpect(jsonPath("$.success", is(false))) -// .andExpect(jsonPath("$.error").exists()) -// .andExpect(jsonPath("$.error.status", is(401))) -// ; -// } -// -// @Test -// public void 올바른_이메일_올바르지_않은_비밀번호로_로그인할_경우_실패() throws Exception { -// ResultActions result = mockMvc.perform(post("/user/login") -// .contentType(MediaType.APPLICATION_JSON) -// .accept(MediaType.APPLICATION_JSON) -// .content("{\"principal\":\"tester@gmail.com\",\"credentials\":\"0000\"}") -// ); -// -// result.andDo(print()) -// .andExpect(status().is4xxClientError()) -// .andExpect(handler().handlerType(UserController.class)) -// .andExpect(handler().methodName("login")) -// .andExpect(jsonPath("$.success", is(false))) -// .andExpect(jsonPath("$.error").exists()) -// .andExpect(jsonPath("$.error.status", is(401))) -// ; -// } -// -// @Test -// public void 올바르지_않은_이메일_올바르지_않은_비밀번호로_로그인할_경우_실패() throws Exception { -// ResultActions result = mockMvc.perform(post("/user/login") -// .contentType(MediaType.APPLICATION_JSON) -// .accept(MediaType.APPLICATION_JSON) -// .content("{\"principal\":\"wrong@gmail.com\",\"credentials\":\"0000\"}") -// ); -// -// result.andDo(print()) -// .andExpect(status().is4xxClientError()) -// .andExpect(handler().handlerType(UserController.class)) -// .andExpect(handler().methodName("login")) -// .andExpect(jsonPath("$.success", is(false))) -// .andExpect(jsonPath("$.error").exists()) -// .andExpect(jsonPath("$.error.status", is(401))) -// ; -// } -// -// @Test -// public void 이메일이_비어있을_경우_로그인할_경우_실패() throws Exception { -// ResultActions result = mockMvc.perform(post("/user/login") -// .contentType(MediaType.APPLICATION_JSON) -// .accept(MediaType.APPLICATION_JSON) -// .content("{\"principal\":\"\",\"credentials\":\"1234\"}") -// ); -// -// result.andDo(print()) -// .andExpect(status().is4xxClientError()) -// .andExpect(handler().handlerType(UserController.class)) -// .andExpect(handler().methodName("login")) -// .andExpect(jsonPath("$.success", is(false))) -// .andExpect(jsonPath("$.error").exists()) -// .andExpect(jsonPath("$.error.status", is(400))) -// ; -// } -// -// @Test -// public void 비밀번호가_비어있을_경우_로그인할_경우_실패() throws Exception { -// ResultActions result = mockMvc.perform(post("/user/login") -// .contentType(MediaType.APPLICATION_JSON) -// .accept(MediaType.APPLICATION_JSON) -// .content("{\"principal\":\"tester@gmail.com\",\"credentials\":\"\"}") -// ); -// -// result.andDo(print()) -// .andExpect(status().is4xxClientError()) -// .andExpect(handler().handlerType(UserController.class)) -// .andExpect(handler().methodName("login")) -// .andExpect(jsonPath("$.success", is(false))) -// .andExpect(jsonPath("$.error").exists()) -// .andExpect(jsonPath("$.error.status", is(400))) -// ; -// } -// -// @Test -// public void 올바른_id로_조회했을경우_성공() throws Exception { -// ResultActions result = mockMvc.perform(get("/user/1") -// .contentType(MediaType.APPLICATION_JSON)); -// -// result.andDo(print()) -// .andExpect(status().isOk()) -// .andExpect(handler().handlerType(UserController.class)) -// .andExpect(handler().methodName("findById")) -// .andExpect(jsonPath("$.success", is(true))) -// .andExpect(jsonPath("$.response.name", is("tester"))) -// .andExpect(jsonPath("$.response.email", is("tester@gmail.com"))) -// .andExpect(jsonPath("$.response.createdAt").exists()) -// .andExpect(jsonPath("$.response.updatedAt").exists()) -// ; -// } -// -// @Test -// public void 존재하지_않은_id로_조회했을경우_실패() throws Exception { -// ResultActions result = mockMvc.perform(get("/user/" + Long.MAX_VALUE) -// .contentType(MediaType.APPLICATION_JSON)); -// -// result.andDo(print()) -// .andExpect(status().is4xxClientError()) -// .andExpect(handler().handlerType(UserController.class)) -// .andExpect(handler().methodName("findById")) -// .andExpect(jsonPath("$.success", is(false))) -// .andExpect(jsonPath("$.error").exists()) -// .andExpect(jsonPath("$.error.status", is(401))) -// ; -// } -// -// @Test -// @Transactional -// public void 올바른_정보를_입력하는_경우_회원가입_성공() throws Exception { -// ResultActions result = mockMvc.perform(put("/user") -// .contentType(MediaType.APPLICATION_JSON) -// .content("{\"name\":\"ssafy\",\"email\":\"ssafy@gmail.com\",\"password\":\"1234\"}")); -// -// result.andDo(print()) -// .andExpect(status().isOk()) -// .andExpect(handler().handlerType(UserController.class)) -// .andExpect(handler().methodName("join")) -// .andExpect(jsonPath("$.success", is(true))) -// .andExpect(jsonPath("$.response.name", is("ssafy"))) -// .andExpect(jsonPath("$.response.email", is("ssafy@gmail.com"))) -// .andExpect(jsonPath("$.response.createdAt").exists()) -// .andExpect(jsonPath("$.response.updatedAt").exists()) -// ; -// } -// -// @Test -// @Transactional -// public void 존재하는_email로_회원가입할_경우_실패() throws Exception { -// ResultActions result = mockMvc.perform(put("/user") -// .contentType(MediaType.APPLICATION_JSON) -// .content("{\"name\":\"tester\",\"email\":\"tester@gmail.com\",\"password\":\"1234\"}")); -// -// result.andDo(print()) -// .andExpect(status().is4xxClientError()) -// .andExpect(handler().handlerType(UserController.class)) -// .andExpect(handler().methodName("join")) -// .andExpect(jsonPath("$.success", is(false))) -// .andExpect(jsonPath("$.error").exists()) -// .andExpect(jsonPath("$.error.status", is(401))) -// ; -// } -// -// @Test -// @Transactional -// public void 올바른_정보로_수정할경우_성공() throws Exception { -// ResultActions result = mockMvc.perform(patch("/user/" + 1) -// .contentType(MediaType.APPLICATION_JSON) -// .content("{\"name\":\"ssafy\"}")); -// -// result.andDo(print()) -// .andExpect(status().isOk()) -// .andExpect(handler().handlerType(UserController.class)) -// .andExpect(handler().methodName("modify")) -// .andExpect(jsonPath("$.success", is(true))) -// ; -// } -// -// @Test -// @Transactional -// public void 올바르지_않은_정보로_수정할경우_실패() throws Exception { -// ResultActions result = mockMvc.perform(patch("/user/" + Long.MAX_VALUE) -// .contentType(MediaType.APPLICATION_JSON) -// .content("{\"name\":\"ssafy\"}")); -// -// result.andDo(print()) -// .andExpect(status().is4xxClientError()) -// .andExpect(handler().handlerType(UserController.class)) -// .andExpect(handler().methodName("modify")) -// .andExpect(jsonPath("$.success", is(false))) -// .andExpect(jsonPath("$.error").exists()) -// .andExpect(jsonPath("$.error.status", is(401))) -// ; -// } -// -// @Test -// @Transactional -// public void 올바른_정보로_삭제할경우_성공() throws Exception { -// ResultActions result = mockMvc.perform(delete("/user/" + 1) -// .contentType(MediaType.APPLICATION_JSON) -// ); -// -// result.andDo(print()) -// .andExpect(status().isOk()) -// .andExpect(handler().handlerType(UserController.class)) -// .andExpect(handler().methodName("delete")) -// .andExpect(jsonPath("$.success", is(true))) -// ; -// } -// -// @Test -// @Transactional -// public void 올바르지_않은_정보로_삭제할경우_실패() throws Exception { -// ResultActions result = mockMvc.perform(delete("/user/" + Long.MAX_VALUE) -// .contentType(MediaType.APPLICATION_JSON) -// ); -// -// result.andDo(print()) -// .andExpect(status().is4xxClientError()) -// .andExpect(handler().handlerType(UserController.class)) -// .andExpect(handler().methodName("delete")) -// .andExpect(jsonPath("$.success", is(false))) -// .andExpect(jsonPath("$.error").exists()) -// .andExpect(jsonPath("$.error.status", is(401))) -// ; -// } + @Autowired + private MockMvc mockMvc; + + @BeforeEach + void setUp(WebApplicationContext context, + RestDocumentationContextProvider provider) { + this.mockMvc = webAppContextSetup(context) + .apply(documentationConfiguration(provider) + .operationPreprocessors() + .withRequestDefaults(prettyPrint()) + .withResponseDefaults(prettyPrint())) + .build(); + } + + @Test + public void 올바른_이메일_AND_비밀번호로_로그인할_경우_성공() throws Exception { + ResultActions result = mockMvc.perform(post("/user/login") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .content("{\"principal\":\"tester@gmail.com\",\n\"credentials\":\"1234\"}") + ); + + result.andDo(print()) + .andExpect(status().isOk()) + .andExpect(handler().handlerType(UserController.class)) + .andExpect(handler().methodName("login")) + .andExpect(jsonPath("$.success", is(true))) + .andExpect(jsonPath("$.response.token").exists()) + .andExpect(jsonPath("$.response.token").isString()) + .andExpect(jsonPath("$.response.user.name", is("tester"))) + .andExpect(jsonPath("$.response.user.email", is("tester@gmail.com"))) + .andExpect(jsonPath("$.response.user.createdAt").exists()) + .andExpect(jsonPath("$.response.user.updatedAt").exists()) + .andDo(document("user/login")) + ; + } + + @Test + public void 올바르지_않은_이메일_올바른_비밀번호로_로그인할_경우_실패() throws Exception { + ResultActions result = mockMvc.perform(post("/user/login") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .content("{\"principal\":\"wrong@gmail.com\",\"credentials\":\"1234\"}") + ); + + result.andDo(print()) + .andExpect(status().is4xxClientError()) + .andExpect(handler().handlerType(UserController.class)) + .andExpect(handler().methodName("login")) + .andExpect(jsonPath("$.success", is(false))) + .andExpect(jsonPath("$.error").exists()) + .andExpect(jsonPath("$.error.status", is(401))) + ; + } + + @Test + public void 올바른_이메일_올바르지_않은_비밀번호로_로그인할_경우_실패() throws Exception { + ResultActions result = mockMvc.perform(post("/user/login") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .content("{\"principal\":\"tester@gmail.com\",\"credentials\":\"0000\"}") + ); + + result.andDo(print()) + .andExpect(status().is4xxClientError()) + .andExpect(handler().handlerType(UserController.class)) + .andExpect(handler().methodName("login")) + .andExpect(jsonPath("$.success", is(false))) + .andExpect(jsonPath("$.error").exists()) + .andExpect(jsonPath("$.error.status", is(401))) + ; + } + + @Test + public void 올바르지_않은_이메일_올바르지_않은_비밀번호로_로그인할_경우_실패() throws Exception { + ResultActions result = mockMvc.perform(post("/user/login") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .content("{\"principal\":\"wrong@gmail.com\",\"credentials\":\"0000\"}") + ); + + result.andDo(print()) + .andExpect(status().is4xxClientError()) + .andExpect(handler().handlerType(UserController.class)) + .andExpect(handler().methodName("login")) + .andExpect(jsonPath("$.success", is(false))) + .andExpect(jsonPath("$.error").exists()) + .andExpect(jsonPath("$.error.status", is(401))) + ; + } + + @Test + public void 이메일이_비어있을_경우_로그인할_경우_실패() throws Exception { + ResultActions result = mockMvc.perform(post("/user/login") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .content("{\"principal\":\"\",\"credentials\":\"1234\"}") + ); + + result.andDo(print()) + .andExpect(status().is4xxClientError()) + .andExpect(handler().handlerType(UserController.class)) + .andExpect(handler().methodName("login")) + .andExpect(jsonPath("$.success", is(false))) + .andExpect(jsonPath("$.error").exists()) + .andExpect(jsonPath("$.error.status", is(400))) + ; + } + + @Test + public void 비밀번호가_비어있을_경우_로그인할_경우_실패() throws Exception { + ResultActions result = mockMvc.perform(post("/user/login") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .content("{\"principal\":\"tester@gmail.com\",\"credentials\":\"\"}") + ); + + result.andDo(print()) + .andExpect(status().is4xxClientError()) + .andExpect(handler().handlerType(UserController.class)) + .andExpect(handler().methodName("login")) + .andExpect(jsonPath("$.success", is(false))) + .andExpect(jsonPath("$.error").exists()) + .andExpect(jsonPath("$.error.status", is(400))) + ; + } + + @Test + public void 올바른_id로_조회했을경우_성공() throws Exception { + ResultActions result = mockMvc.perform(get("/user/1") + .contentType(MediaType.APPLICATION_JSON)); + + result.andDo(print()) + .andExpect(status().isOk()) + .andExpect(handler().handlerType(UserController.class)) + .andExpect(handler().methodName("findById")) + .andExpect(jsonPath("$.success", is(true))) + .andExpect(jsonPath("$.response.name", is("tester"))) + .andExpect(jsonPath("$.response.email", is("tester@gmail.com"))) + .andExpect(jsonPath("$.response.createdAt").exists()) + .andExpect(jsonPath("$.response.updatedAt").exists()) + .andDo(document("user/find")) + ; + } + + @Test + public void 존재하지_않은_id로_조회했을경우_실패() throws Exception { + ResultActions result = mockMvc.perform(get("/user/" + Long.MAX_VALUE) + .contentType(MediaType.APPLICATION_JSON)); + + result.andDo(print()) + .andExpect(status().is4xxClientError()) + .andExpect(handler().handlerType(UserController.class)) + .andExpect(handler().methodName("findById")) + .andExpect(jsonPath("$.success", is(false))) + .andExpect(jsonPath("$.error").exists()) + .andExpect(jsonPath("$.error.status", is(401))) + ; + } + + @Test + @Transactional + public void 올바른_정보를_입력하는_경우_회원가입_성공() throws Exception { + ResultActions result = mockMvc.perform(post("/user/join") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"name\":\"ssafy\",\"email\":\"ssafy@gmail.com\",\"password\":\"1234\"}")); + + result.andDo(print()) + .andExpect(status().isOk()) + .andExpect(handler().handlerType(UserController.class)) + .andExpect(handler().methodName("join")) + .andExpect(jsonPath("$.success", is(true))) + .andExpect(jsonPath("$.response.name", is("ssafy"))) + .andExpect(jsonPath("$.response.email", is("ssafy@gmail.com"))) + .andExpect(jsonPath("$.response.createdAt").exists()) + .andExpect(jsonPath("$.response.updatedAt").exists()) + .andDo(document("user/join")) + ; + } + + @Test + @Transactional + public void 존재하는_email로_회원가입할_경우_실패() throws Exception { + ResultActions result = mockMvc.perform(post("/user/join") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"name\":\"tester\",\"email\":\"tester@gmail.com\",\"password\":\"1234\"}")); + + result.andDo(print()) + .andExpect(status().is4xxClientError()) + .andExpect(handler().handlerType(UserController.class)) + .andExpect(handler().methodName("join")) + .andExpect(jsonPath("$.success", is(false))) + .andExpect(jsonPath("$.error").exists()) + .andExpect(jsonPath("$.error.status", is(401))) + ; + } + + @Test + @Transactional + public void 올바른_정보로_수정할경우_성공() throws Exception { + ResultActions result = mockMvc.perform(put("/user/" + 1) + .contentType(MediaType.APPLICATION_JSON) + .content("{\"name\":\"ssafy\"}")); + + result.andDo(print()) + .andExpect(status().isOk()) + .andExpect(handler().handlerType(UserController.class)) + .andExpect(handler().methodName("modify")) + .andExpect(jsonPath("$.success", is(true))) + .andDo(document("user/modify")) + ; + } + + @Test + @Transactional + public void 올바르지_않은_정보로_수정할경우_실패() throws Exception { + ResultActions result = mockMvc.perform(put("/user/" + Long.MAX_VALUE) + .contentType(MediaType.APPLICATION_JSON) + .content("{\"name\":\"ssafy\"}")); + + result.andDo(print()) + .andExpect(status().is4xxClientError()) + .andExpect(handler().handlerType(UserController.class)) + .andExpect(handler().methodName("modify")) + .andExpect(jsonPath("$.success", is(false))) + .andExpect(jsonPath("$.error").exists()) + .andExpect(jsonPath("$.error.status", is(401))) + ; + } + + @Test + @Transactional + public void 올바른_정보로_삭제할경우_성공() throws Exception { + ResultActions result = mockMvc.perform(delete("/user/" + 1) + .contentType(MediaType.APPLICATION_JSON) + ); + + result.andDo(print()) + .andExpect(status().isOk()) + .andExpect(handler().handlerType(UserController.class)) + .andExpect(handler().methodName("delete")) + .andExpect(jsonPath("$.success", is(true))) + .andDo(document("user/delete")) + ; + } + + @Test + @Transactional + public void 올바르지_않은_정보로_삭제할경우_실패() throws Exception { + ResultActions result = mockMvc.perform(delete("/user/" + Long.MAX_VALUE) + .contentType(MediaType.APPLICATION_JSON) + ); + + result.andDo(print()) + .andExpect(status().is4xxClientError()) + .andExpect(handler().handlerType(UserController.class)) + .andExpect(handler().methodName("delete")) + .andExpect(jsonPath("$.success", is(false))) + .andExpect(jsonPath("$.error").exists()) + .andExpect(jsonPath("$.error.status", is(401))) + ; + } } \ No newline at end of file From 13886bd28a1185d965a636c808e07ba3fd697796 Mon Sep 17 00:00:00 2001 From: hellomatia Date: Tue, 21 May 2024 17:46:54 +0900 Subject: [PATCH 06/11] =?UTF-8?q?feat:=20USER=20API=20DOCS=20=ED=8F=AC?= =?UTF-8?q?=EB=A7=B7=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/docs/asciidoc/user.adoc | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/docs/asciidoc/user.adoc diff --git a/src/docs/asciidoc/user.adoc b/src/docs/asciidoc/user.adoc new file mode 100644 index 0000000..e8ba750 --- /dev/null +++ b/src/docs/asciidoc/user.adoc @@ -0,0 +1,38 @@ += USER API 문서 +:doctype: book +:icons: font +:source-highlighter: highlightjs +:toc: left +:toclevels: 3 + +== 로그인 + +**Request** +include::{snippets}/user/login/http-request.adoc[] + +**Response** +include::{snippets}/user/login/http-response.adoc[] + +== 회원 가입 + +**Request** +include::{snippets}/user/join/http-request.adoc[] + +**Response** +include::{snippets}/user/join/http-response.adoc[] + +== 회원 수정 + +**Request** +include::{snippets}/user/modify/http-request.adoc[] + +**Response** +include::{snippets}/user/modify/http-response.adoc[] + +== 회원 삭제 + +**Request** +include::{snippets}/user/delete/http-request.adoc[] + +**Response** +include::{snippets}/user/delete/http-response.adoc[] \ No newline at end of file From 5f72dc8fcda6dc5f2c8e5933199bbda07454362d Mon Sep 17 00:00:00 2001 From: hellomatia Date: Wed, 22 May 2024 01:09:33 +0900 Subject: [PATCH 07/11] =?UTF-8?q?feat:=20userController=20rest=20docs=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/WithMockJwtAuthentication.java | 17 +++++ ...tAuthenticationSecurityContextFactory.java | 23 +++++++ .../user/controller/UserControllerTest.java | 63 +++++++++++++------ 3 files changed, 85 insertions(+), 18 deletions(-) create mode 100644 src/test/java/com/mlog/security/WithMockJwtAuthentication.java create mode 100644 src/test/java/com/mlog/security/WithMockJwtAuthenticationSecurityContextFactory.java diff --git a/src/test/java/com/mlog/security/WithMockJwtAuthentication.java b/src/test/java/com/mlog/security/WithMockJwtAuthentication.java new file mode 100644 index 0000000..9b2781a --- /dev/null +++ b/src/test/java/com/mlog/security/WithMockJwtAuthentication.java @@ -0,0 +1,17 @@ +package com.mlog.security; + +import org.springframework.security.test.context.support.WithSecurityContext; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +@WithSecurityContext(factory = WithMockJwtAuthenticationSecurityContextFactory.class) +public @interface WithMockJwtAuthentication { + + long id() default 1L; + + String name() default "tester"; + + String role() default "ROLE_USER"; +} diff --git a/src/test/java/com/mlog/security/WithMockJwtAuthenticationSecurityContextFactory.java b/src/test/java/com/mlog/security/WithMockJwtAuthenticationSecurityContextFactory.java new file mode 100644 index 0000000..06f9d6a --- /dev/null +++ b/src/test/java/com/mlog/security/WithMockJwtAuthenticationSecurityContextFactory.java @@ -0,0 +1,23 @@ +package com.mlog.security; + +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.test.context.support.WithSecurityContextFactory; + +import static org.springframework.security.core.authority.AuthorityUtils.createAuthorityList; + +public class WithMockJwtAuthenticationSecurityContextFactory implements WithSecurityContextFactory { + + @Override + public SecurityContext createSecurityContext(WithMockJwtAuthentication annotation) { + SecurityContext context = SecurityContextHolder.createEmptyContext(); + JwtAuthenticationToken authentication = + new JwtAuthenticationToken( + new JwtAuthentication(annotation.id(), annotation.name()), + null, + createAuthorityList(annotation.role()) + ); + context.setAuthentication(authentication); + return context; + } +} diff --git a/src/test/java/com/mlog/user/controller/UserControllerTest.java b/src/test/java/com/mlog/user/controller/UserControllerTest.java index 182ca8d..f6183d7 100644 --- a/src/test/java/com/mlog/user/controller/UserControllerTest.java +++ b/src/test/java/com/mlog/user/controller/UserControllerTest.java @@ -1,6 +1,9 @@ package com.mlog.user.controller; +import com.mlog.config.JwtTokenConfigure; +import com.mlog.security.WithMockJwtAuthentication; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -16,6 +19,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.context.WebApplicationContext; +import static org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric; import static org.hamcrest.Matchers.is; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; @@ -26,15 +30,16 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; -@ExtendWith({SpringExtension.class, RestDocumentationExtension.class}) @SpringBootTest -@AutoConfigureRestDocs @AutoConfigureMockMvc +@ExtendWith({SpringExtension.class, RestDocumentationExtension.class}) class UserControllerTest { - @Autowired private MockMvc mockMvc; + @Autowired + private JwtTokenConfigure jwtTokenConfigure; + @BeforeEach void setUp(WebApplicationContext context, RestDocumentationContextProvider provider) { @@ -53,7 +58,6 @@ void setUp(WebApplicationContext context, .accept(MediaType.APPLICATION_JSON) .content("{\"principal\":\"tester@gmail.com\",\n\"credentials\":\"1234\"}") ); - result.andDo(print()) .andExpect(status().isOk()) .andExpect(handler().handlerType(UserController.class)) @@ -76,7 +80,6 @@ void setUp(WebApplicationContext context, .accept(MediaType.APPLICATION_JSON) .content("{\"principal\":\"wrong@gmail.com\",\"credentials\":\"1234\"}") ); - result.andDo(print()) .andExpect(status().is4xxClientError()) .andExpect(handler().handlerType(UserController.class)) @@ -94,7 +97,6 @@ void setUp(WebApplicationContext context, .accept(MediaType.APPLICATION_JSON) .content("{\"principal\":\"tester@gmail.com\",\"credentials\":\"0000\"}") ); - result.andDo(print()) .andExpect(status().is4xxClientError()) .andExpect(handler().handlerType(UserController.class)) @@ -112,7 +114,6 @@ void setUp(WebApplicationContext context, .accept(MediaType.APPLICATION_JSON) .content("{\"principal\":\"wrong@gmail.com\",\"credentials\":\"0000\"}") ); - result.andDo(print()) .andExpect(status().is4xxClientError()) .andExpect(handler().handlerType(UserController.class)) @@ -130,7 +131,6 @@ void setUp(WebApplicationContext context, .accept(MediaType.APPLICATION_JSON) .content("{\"principal\":\"\",\"credentials\":\"1234\"}") ); - result.andDo(print()) .andExpect(status().is4xxClientError()) .andExpect(handler().handlerType(UserController.class)) @@ -148,7 +148,6 @@ void setUp(WebApplicationContext context, .accept(MediaType.APPLICATION_JSON) .content("{\"principal\":\"tester@gmail.com\",\"credentials\":\"\"}") ); - result.andDo(print()) .andExpect(status().is4xxClientError()) .andExpect(handler().handlerType(UserController.class)) @@ -163,7 +162,6 @@ void setUp(WebApplicationContext context, public void 올바른_id로_조회했을경우_성공() throws Exception { ResultActions result = mockMvc.perform(get("/user/1") .contentType(MediaType.APPLICATION_JSON)); - result.andDo(print()) .andExpect(status().isOk()) .andExpect(handler().handlerType(UserController.class)) @@ -181,7 +179,6 @@ void setUp(WebApplicationContext context, public void 존재하지_않은_id로_조회했을경우_실패() throws Exception { ResultActions result = mockMvc.perform(get("/user/" + Long.MAX_VALUE) .contentType(MediaType.APPLICATION_JSON)); - result.andDo(print()) .andExpect(status().is4xxClientError()) .andExpect(handler().handlerType(UserController.class)) @@ -198,7 +195,6 @@ void setUp(WebApplicationContext context, ResultActions result = mockMvc.perform(post("/user/join") .contentType(MediaType.APPLICATION_JSON) .content("{\"name\":\"ssafy\",\"email\":\"ssafy@gmail.com\",\"password\":\"1234\"}")); - result.andDo(print()) .andExpect(status().isOk()) .andExpect(handler().handlerType(UserController.class)) @@ -218,7 +214,6 @@ void setUp(WebApplicationContext context, ResultActions result = mockMvc.perform(post("/user/join") .contentType(MediaType.APPLICATION_JSON) .content("{\"name\":\"tester\",\"email\":\"tester@gmail.com\",\"password\":\"1234\"}")); - result.andDo(print()) .andExpect(status().is4xxClientError()) .andExpect(handler().handlerType(UserController.class)) @@ -235,7 +230,6 @@ void setUp(WebApplicationContext context, ResultActions result = mockMvc.perform(put("/user/" + 1) .contentType(MediaType.APPLICATION_JSON) .content("{\"name\":\"ssafy\"}")); - result.andDo(print()) .andExpect(status().isOk()) .andExpect(handler().handlerType(UserController.class)) @@ -251,7 +245,6 @@ void setUp(WebApplicationContext context, ResultActions result = mockMvc.perform(put("/user/" + Long.MAX_VALUE) .contentType(MediaType.APPLICATION_JSON) .content("{\"name\":\"ssafy\"}")); - result.andDo(print()) .andExpect(status().is4xxClientError()) .andExpect(handler().handlerType(UserController.class)) @@ -268,7 +261,6 @@ void setUp(WebApplicationContext context, ResultActions result = mockMvc.perform(delete("/user/" + 1) .contentType(MediaType.APPLICATION_JSON) ); - result.andDo(print()) .andExpect(status().isOk()) .andExpect(handler().handlerType(UserController.class)) @@ -284,7 +276,6 @@ void setUp(WebApplicationContext context, ResultActions result = mockMvc.perform(delete("/user/" + Long.MAX_VALUE) .contentType(MediaType.APPLICATION_JSON) ); - result.andDo(print()) .andExpect(status().is4xxClientError()) .andExpect(handler().handlerType(UserController.class)) @@ -294,4 +285,40 @@ void setUp(WebApplicationContext context, .andExpect(jsonPath("$.error.status", is(401))) ; } -} \ No newline at end of file + + @Test + @WithMockJwtAuthentication + @DisplayName("내 정보 조회 성공 테스트 (토큰이 올바른 경우)") + void meSuccessTest() throws Exception { + ResultActions result = mockMvc.perform( + get("/user/me") + .accept(MediaType.APPLICATION_JSON) + ); + result.andDo(print()) + .andExpect(status().isOk()) + .andExpect(handler().handlerType(UserController.class)) + .andExpect(handler().methodName("me")) + .andExpect(jsonPath("$.success", is(true))) + .andExpect(jsonPath("$.response.name", is("tester"))) + .andExpect(jsonPath("$.response.email", is("tester@gmail.com"))) + .andDo(document("user/me")) + ; + } + + @Test + @DisplayName("내 정보 조회 실패 테스트 (토큰이 올바르지 않을 경우)") + void meFailureTest() throws Exception { + ResultActions result = mockMvc.perform( + get("/user/me") + .accept(MediaType.APPLICATION_JSON) + .header(jwtTokenConfigure.getHeader(), "Bearer " + randomAlphanumeric(60)) + ); + result.andDo(print()) + .andExpect(status().is4xxClientError()) + .andExpect(jsonPath("$.success", is(false))) + .andExpect(jsonPath("$.error").exists()) + .andExpect(jsonPath("$.error.status", is(401))) + .andExpect(jsonPath("$.error.message", is("invalid authentication"))) + ; + } +} From d9d321a4934a4c4f3d3b972c0151b620681cb40d Mon Sep 17 00:00:00 2001 From: hellomatia Date: Wed, 22 May 2024 01:10:25 +0900 Subject: [PATCH 08/11] =?UTF-8?q?feat:=20url=20=EC=A0=91=EA=B7=BC=20?= =?UTF-8?q?=EC=88=98=EC=A4=80=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/mlog/config/WebSecurityConfigure.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/mlog/config/WebSecurityConfigure.java b/src/main/java/com/mlog/config/WebSecurityConfigure.java index 8f11672..a2ecbfa 100644 --- a/src/main/java/com/mlog/config/WebSecurityConfigure.java +++ b/src/main/java/com/mlog/config/WebSecurityConfigure.java @@ -69,7 +69,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .authorizeHttpRequests(auth -> auth .requestMatchers("/user/login").permitAll() - .anyRequest().permitAll()) + .anyRequest().authenticated()) .formLogin(AbstractHttpConfigurer::disable); From 6742b2be3de0b9e71bf74b55167ee77c4594d0a1 Mon Sep 17 00:00:00 2001 From: hellomatia Date: Wed, 22 May 2024 01:10:51 +0900 Subject: [PATCH 09/11] =?UTF-8?q?feat:=20travelController=20rest=20docs=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/TravelControllerTest.java | 180 +++++++++++++++--- 1 file changed, 155 insertions(+), 25 deletions(-) diff --git a/src/test/java/com/mlog/travel/controller/TravelControllerTest.java b/src/test/java/com/mlog/travel/controller/TravelControllerTest.java index fff3654..4493f88 100644 --- a/src/test/java/com/mlog/travel/controller/TravelControllerTest.java +++ b/src/test/java/com/mlog/travel/controller/TravelControllerTest.java @@ -1,40 +1,170 @@ package com.mlog.travel.controller; -import org.json.JSONObject; +import com.mlog.security.WithMockJwtAuthentication; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; -import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.is; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; @SpringBootTest @AutoConfigureMockMvc +@ExtendWith({SpringExtension.class, RestDocumentationExtension.class}) class TravelControllerTest { -// @Autowired -// private MockMvc mockMvc; -// -// @Test -// public void travel_테스트_예시() throws Exception { -// -// MvcResult result = mockMvc.perform(get("/travel") -// .contentType(MediaType.APPLICATION_JSON)) -// .andExpect(status().isOk()) -// .andReturn(); -// -// JSONObject response = new JSONObject(result.getResponse().getContentAsString()); -// assertThat(response.get("success")) -// .isEqualTo(true); -// assertThat("hello travel") -// .isEqualTo(response.get("response")); -// assertThat(response.get("error")) -// .isEqualTo(null); -// } - -} \ No newline at end of file + @Autowired + private MockMvc mockMvc; + + @BeforeEach + void setUp(WebApplicationContext context, + RestDocumentationContextProvider provider) { + this.mockMvc = webAppContextSetup(context) + .apply(documentationConfiguration(provider) + .operationPreprocessors() + .withRequestDefaults(prettyPrint()) + .withResponseDefaults(prettyPrint())) + .build(); + } + + @Test + @WithMockJwtAuthentication + @Transactional + public void 여행정보_저장() throws Exception { + ResultActions result = mockMvc.perform(post("/travel") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .content("{" + + "\"title\": \"행복한 여행\",\n" + + " \"description\": \"한줄평!! 너무 좋습니다!\",\n" + + " \"image\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAiiiiiiiiiiiiiiiiiiiiiiiii\",\n" + + " \"lat\": 35.20396241242666,\n" + + " \"lng\": 126.80639199013274,\n" + + " \"startDate\": \"2024-05-21T15:19:49.598Z\",\n" + + " \"endDate\": \"2024-05-29T15:19:49.598Z\",\n" + + " \"rating\": 5,\n" + + " \"detailedSchedules\": [\n" + + " {\n" + + " \"seq\": 1,\n" + + " \"title\": \"상세 일정1\",\n" + + " \"description\": \"상세 일정 설명 1\",\n" + + " \"images\": [\n" + + " \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAiiiiiiiiiiiiiiiiiiiiiiiii\",\n" + + " \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAiiiiiiiiiiiiiiiiiiiiiiiii\"\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"seq\": 2,\n" + + " \"title\": \"상세 일정2\",\n" + + " \"description\": \"상세 일정 설명 2\",\n" + + " \"images\": [\n" + + " \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAiiiiiiiiiiiiiiiiiiiiiiiii\",\n" + + " \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAiiiiiiiiiiiiiiiiiiiiiiiii\"\n" + + " ]\n" + + " }\n" + + " ]\n" + + "}") + ); + result.andDo(print()) + .andExpect(status().isOk()) + .andExpect(handler().handlerType(TravelController.class)) + .andExpect(handler().methodName("saveTravel")) + .andExpect(jsonPath("$.success", is(true))) + .andExpect(jsonPath("$.response", is(true))) + .andExpect(jsonPath("$.error").isEmpty()) + .andDo(document("travel/save")) + ; + } + + @Test + @WithMockJwtAuthentication + public void 사용자_여행정보_리스트_가져오기() throws Exception { + ResultActions result = mockMvc.perform(get("/travel") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + ); + result.andDo(print()) + .andExpect(status().isOk()) + .andExpect(handler().handlerType(TravelController.class)) + .andExpect(handler().methodName("travelListResult")) + .andExpect(jsonPath("$.success", is(true))) + .andExpect(jsonPath("$.response.travelList").exists()) + .andExpect(jsonPath("$.response.travelList[0].id").isNumber()) + .andExpect(jsonPath("$.response.travelList[0].description").isString()) + .andExpect(jsonPath("$.response.travelList[0].lat").isString()) + .andExpect(jsonPath("$.response.travelList[0].lng").isString()) + .andExpect(jsonPath("$.response.travelList[0].imageUrl").isString()) + .andExpect(jsonPath("$.response.travelList[0].title").exists()) + .andExpect(jsonPath("$.error").isEmpty()) + .andDo(document("travel/list")) + ; + } + + @Test + public void 사용자_여행상세정보_가져오기() throws Exception { + ResultActions result = mockMvc.perform(get("/travel/6") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + ); + result.andDo(print()) + .andExpect(status().isOk()) + .andExpect(handler().handlerType(TravelController.class)) + .andExpect(handler().methodName("travelDetailResult")) + .andExpect(jsonPath("$.success", is(true))) + .andExpect(jsonPath("$.response").exists()) + .andExpect(jsonPath("$.response.title").isString()) + .andExpect(jsonPath("$.response.description").isString()) + .andExpect(jsonPath("$.response.lat").isString()) + .andExpect(jsonPath("$.response.lng").isString()) + .andExpect(jsonPath("$.response.imageUrl").isString()) + .andExpect(jsonPath("$.response.startDate").isString()) + .andExpect(jsonPath("$.response.endDate").isString()) + .andExpect(jsonPath("$.response.rating").isNumber()) + .andExpect(jsonPath("$.response.detailedSchedules").isArray()) + .andExpect(jsonPath("$.response.detailedSchedules[0].id").isNumber()) + .andExpect(jsonPath("$.response.detailedSchedules[0].seq").isNumber()) + .andExpect(jsonPath("$.response.detailedSchedules[0].title").isString()) + .andExpect(jsonPath("$.response.detailedSchedules[0].description").isString()) + .andExpect(jsonPath("$.error").isEmpty()) + .andDo(document("travel/detail")) + ; + } + + @Test + public void 사용자_여행상세사진리스트_가져오기() throws Exception { + ResultActions result = mockMvc.perform(get("/travel/photos/12") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + ); + result.andDo(print()) + .andExpect(status().isOk()) + .andExpect(handler().handlerType(TravelController.class)) + .andExpect(handler().methodName("travelDetailResultPhoto")) + .andExpect(jsonPath("$.success", is(true))) + .andExpect(jsonPath("$.response").exists()) + .andExpect(jsonPath("$.response.travelPhotoList").isArray()) + .andExpect(jsonPath("$.response.travelPhotoList[0].imageUrl").isString()) + .andExpect(jsonPath("$.error").isEmpty()) + .andDo(document("travel/photos")) + ; + } +} From 331a67cbdcaa7bfb12bc001886c06606b93d471b Mon Sep 17 00:00:00 2001 From: hellomatia Date: Wed, 22 May 2024 01:24:02 +0900 Subject: [PATCH 10/11] =?UTF-8?q?feat:=20'/'=EB=A1=9C=20=EC=A0=91=EA=B7=BC?= =?UTF-8?q?=EC=8B=9C=20api=20=EB=AC=B8=EC=84=9C=EA=B0=80=20=EB=B0=94?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=B4=EC=9D=B4=EB=8F=84=EB=A1=9D=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- src/docs/asciidoc/index.adoc | 91 +++++++++++++++++++ src/docs/asciidoc/user.adoc | 38 -------- .../com/mlog/config/WebSecurityConfigure.java | 2 +- 4 files changed, 93 insertions(+), 40 deletions(-) create mode 100644 src/docs/asciidoc/index.adoc delete mode 100644 src/docs/asciidoc/user.adoc diff --git a/build.gradle b/build.gradle index 5427e80..950aa68 100644 --- a/build.gradle +++ b/build.gradle @@ -108,7 +108,7 @@ tasks.register('copyDocument', Copy) { dependsOn asciidoctor from file("build/docs/asciidoc/") - into file("src/main/resources/static/docs") + into file("src/main/resources/static/") } build { diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc new file mode 100644 index 0000000..32d18a7 --- /dev/null +++ b/src/docs/asciidoc/index.adoc @@ -0,0 +1,91 @@ += M-LOG API 문서 +:doctype: book +:icons: font +:source-highlighter: highlightjs +:toc: left +:toclevels: 3 + +== 회원 + +=== 로그인 +**Request** +include::{snippets}/user/login/http-request.adoc[] + +**Response** +include::{snippets}/user/login/http-response.adoc[] + +=== 회원 가입 + +**Request** +include::{snippets}/user/join/http-request.adoc[] + +**Response** +include::{snippets}/user/join/http-response.adoc[] + +=== 회원 수정 + +**Request** +include::{snippets}/user/modify/http-request.adoc[] + +**Response** +include::{snippets}/user/modify/http-response.adoc[] + +=== 회원 삭제 + +**Request** +include::{snippets}/user/delete/http-request.adoc[] + +**Response** +include::{snippets}/user/delete/http-response.adoc[] + +=== 회원 정보 조회 + +==== 1. JWT 토큰 기반 +**Request** +include::{snippets}/user/me/http-request.adoc[] + +**Response** +include::{snippets}/user/me/http-response.adoc[] + +--- + +==== 2. ID 기반 +**Request** +include::{snippets}/user/find/http-request.adoc[] + +**Response** +include::{snippets}/user/find/http-response.adoc[] + +== 여행 + +=== 여행 정보 저장 (JWT 기반) + +**Request** +include::{snippets}/travel/save/http-request.adoc[] + +**Response** +include::{snippets}/travel/save/http-response.adoc[] + +=== 여행 정보 리스트 조회 (JWT 기반) + +**Request** +include::{snippets}/travel/list/http-request.adoc[] + +**Response** +include::{snippets}/travel/list/http-response.adoc[] + +=== 여행 상세 정보 조회 + +**Request** +include::{snippets}/travel/detail/http-request.adoc[] + +**Response** +include::{snippets}/travel/detail/http-response.adoc[] + +=== 여행 상세 사진 조회 + +**Request** +include::{snippets}/travel/photos/http-request.adoc[] + +**Response** +include::{snippets}/travel/photos/http-response.adoc[] \ No newline at end of file diff --git a/src/docs/asciidoc/user.adoc b/src/docs/asciidoc/user.adoc deleted file mode 100644 index e8ba750..0000000 --- a/src/docs/asciidoc/user.adoc +++ /dev/null @@ -1,38 +0,0 @@ -= USER API 문서 -:doctype: book -:icons: font -:source-highlighter: highlightjs -:toc: left -:toclevels: 3 - -== 로그인 - -**Request** -include::{snippets}/user/login/http-request.adoc[] - -**Response** -include::{snippets}/user/login/http-response.adoc[] - -== 회원 가입 - -**Request** -include::{snippets}/user/join/http-request.adoc[] - -**Response** -include::{snippets}/user/join/http-response.adoc[] - -== 회원 수정 - -**Request** -include::{snippets}/user/modify/http-request.adoc[] - -**Response** -include::{snippets}/user/modify/http-response.adoc[] - -== 회원 삭제 - -**Request** -include::{snippets}/user/delete/http-request.adoc[] - -**Response** -include::{snippets}/user/delete/http-response.adoc[] \ No newline at end of file diff --git a/src/main/java/com/mlog/config/WebSecurityConfigure.java b/src/main/java/com/mlog/config/WebSecurityConfigure.java index a2ecbfa..56c836a 100644 --- a/src/main/java/com/mlog/config/WebSecurityConfigure.java +++ b/src/main/java/com/mlog/config/WebSecurityConfigure.java @@ -68,7 +68,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth - .requestMatchers("/user/login").permitAll() + .requestMatchers("/user/login", "/", "/index.html").permitAll() .anyRequest().authenticated()) .formLogin(AbstractHttpConfigurer::disable); From 6382fc204e356458ee9129bae61ae548b42767a9 Mon Sep 17 00:00:00 2001 From: hellomatia Date: Wed, 22 May 2024 01:39:55 +0900 Subject: [PATCH 11/11] =?UTF-8?q?style:=20=EC=BD=94=EB=93=9C=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/mlog/error/GeneralExceptionHandler.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/mlog/error/GeneralExceptionHandler.java b/src/main/java/com/mlog/error/GeneralExceptionHandler.java index 0a4603a..9e6ef17 100644 --- a/src/main/java/com/mlog/error/GeneralExceptionHandler.java +++ b/src/main/java/com/mlog/error/GeneralExceptionHandler.java @@ -72,5 +72,4 @@ public ResponseEntity handleException(Exception e) { public ResponseEntity handleUnauthorizedException(Exception e) { return newResponse(e, HttpStatus.UNAUTHORIZED); } - -} \ No newline at end of file +}