From 0665b78cc715ac8acf3d1b530bae0db4d6df0bce Mon Sep 17 00:00:00 2001 From: can019 Date: Tue, 23 Sep 2025 15:13:16 +0900 Subject: [PATCH 1/7] =?UTF-8?q?test:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D,=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=84=B8?= =?UTF-8?q?=EC=85=98=20=EC=B2=B4=ED=81=AC,=20=EC=82=AC=EC=9A=A9=EC=9E=90?= =?UTF-8?q?=20=EA=B6=8C=ED=95=9C=20=EC=9A=94=EC=B2=AD=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tests/auth/AuthApiIntegrationTest.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/user-service/src/test/java/site/icebang/integration/tests/auth/AuthApiIntegrationTest.java b/apps/user-service/src/test/java/site/icebang/integration/tests/auth/AuthApiIntegrationTest.java index 4fe3b00d..607f63a3 100644 --- a/apps/user-service/src/test/java/site/icebang/integration/tests/auth/AuthApiIntegrationTest.java +++ b/apps/user-service/src/test/java/site/icebang/integration/tests/auth/AuthApiIntegrationTest.java @@ -10,6 +10,7 @@ import java.util.HashMap; import java.util.Map; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.http.*; @@ -29,7 +30,7 @@ class AuthApiIntegrationTest extends IntegrationTestSupport { @Test @DisplayName("사용자 로그인 성공") - void login_success() throws Exception { + void loginSuccess() throws Exception { // given Map loginRequest = new HashMap<>(); loginRequest.put("email", "admin@icebang.site"); @@ -81,9 +82,21 @@ void login_success() throws Exception { .build()))); } + @Disabled + @DisplayName("사용자 등록") + void register() throws Exception {} + + @Disabled + @DisplayName("사용자 세션 체크") + void checkSession() throws Exception {} + + @Disabled + @DisplayName("사용자 권한 요청") + void userPermission() throws Exception {} + @Test @DisplayName("사용자 로그아웃 성공") - void logout_success() throws Exception { + void logoutSuccess() throws Exception { // given - 먼저 로그인 Map loginRequest = new HashMap<>(); loginRequest.put("email", "admin@icebang.site"); From 77f9061a03f6cdcaed0141aa735a351285e4bb8c Mon Sep 17 00:00:00 2001 From: can019 Date: Tue, 23 Sep 2025 15:40:01 +0900 Subject: [PATCH 2/7] test: User register integration test --- .../tests/auth/AuthApiIntegrationTest.java | 117 +++++++++++++++++- 1 file changed, 114 insertions(+), 3 deletions(-) diff --git a/apps/user-service/src/test/java/site/icebang/integration/tests/auth/AuthApiIntegrationTest.java b/apps/user-service/src/test/java/site/icebang/integration/tests/auth/AuthApiIntegrationTest.java index 607f63a3..d0cbd60a 100644 --- a/apps/user-service/src/test/java/site/icebang/integration/tests/auth/AuthApiIntegrationTest.java +++ b/apps/user-service/src/test/java/site/icebang/integration/tests/auth/AuthApiIntegrationTest.java @@ -7,6 +7,7 @@ import static org.springframework.restdocs.payload.PayloadDocumentation.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -16,6 +17,7 @@ import org.springframework.http.*; import org.springframework.mock.web.MockHttpSession; import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.security.test.context.support.WithUserDetails; import org.springframework.test.context.jdbc.Sql; import org.springframework.transaction.annotation.Transactional; @@ -82,9 +84,118 @@ void loginSuccess() throws Exception { .build()))); } - @Disabled - @DisplayName("사용자 등록") - void register() throws Exception {} + @Test + @DisplayName("사용자 등록 성공") + @WithUserDetails("admin@icebang.site") + void registerSuccess() throws Exception { + // given + Map registerRequest = new HashMap<>(); + registerRequest.put("name", "홍길동"); + registerRequest.put("email", "hong@icebang.site"); + registerRequest.put("orgId", 1); + registerRequest.put("deptId", 1); + registerRequest.put("positionId", 1); + registerRequest.put("roleIds", Arrays.asList(1, 2)); + + // MockMvc로 REST Docs + OpenAPI 생성 + mockMvc + .perform( + post(getApiUrlForDocs("/v0/auth/register")) + .contentType(MediaType.APPLICATION_JSON) + .header("Origin", "https://admin.icebang.site") + .header("Referer", "https://admin.icebang.site/") + .content(objectMapper.writeValueAsString(registerRequest))) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.success").value(true)) + .andExpect(jsonPath("$.status").value("CREATED")) + .andExpect(jsonPath("$.message").value("OK")) + .andExpect(jsonPath("$.data").isEmpty()) + .andDo( + document( + "auth-register", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Authentication") + .summary("사용자 회원가입") + .description("새로운 사용자 계정을 생성합니다") + .requestFields( + fieldWithPath("name").type(JsonFieldType.STRING).description("사용자명"), + fieldWithPath("email") + .type(JsonFieldType.STRING) + .description("사용자 이메일 주소"), + fieldWithPath("orgId").type(JsonFieldType.NUMBER).description("조직 ID"), + fieldWithPath("deptId").type(JsonFieldType.NUMBER).description("부서 ID"), + fieldWithPath("positionId") + .type(JsonFieldType.NUMBER) + .description("직책 ID"), + fieldWithPath("roleIds") + .type(JsonFieldType.ARRAY) + .description("역할 ID 목록")) + .responseFields( + fieldWithPath("success") + .type(JsonFieldType.BOOLEAN) + .description("요청 성공 여부"), + fieldWithPath("data") + .type(JsonFieldType.NULL) + .description("응답 데이터 (회원가입 성공 시 null)"), + fieldWithPath("message") + .type(JsonFieldType.STRING) + .description("응답 메시지"), + fieldWithPath("status") + .type(JsonFieldType.STRING) + .description("HTTP 상태")) + .build()))); + } + + @Test + @DisplayName("사용자 등록 실패 - 이메일 양식 오류") + @WithUserDetails("admin@icebang.site") + void registerFailureWhenInvalidEmail() throws Exception { + // given + Map registerRequest = new HashMap<>(); + registerRequest.put("name", "홍길동"); + registerRequest.put("email", "invalid-email"); // 잘못된 이메일 형식 + registerRequest.put("orgId", 1); + registerRequest.put("deptId", 1); + registerRequest.put("positionId", 1); + registerRequest.put("roleIds", Arrays.asList(1)); + + // when & then + mockMvc + .perform( + post(getApiUrlForDocs("/v0/auth/register")) + .contentType(MediaType.APPLICATION_JSON) + .header("Origin", "https://admin.icebang.site") + .header("Referer", "https://admin.icebang.site/") + .content(objectMapper.writeValueAsString(registerRequest))) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.success").value(false)) + .andExpect(jsonPath("$.status").value("BAD_REQUEST")); + } + + @Test + @DisplayName("사용자 등록 실패 - 필수 필드 누락") + @WithUserDetails("admin@icebang.site") + void registerFailureWhenMissingRequiredFields() throws Exception { + // given - 필수 필드 누락 + Map registerRequest = new HashMap<>(); + registerRequest.put("email", "test@icebang.site"); + // name, orgId, deptId, positionId, roleIds 누락 + + // when & then + mockMvc + .perform( + post(getApiUrlForDocs("/v0/auth/register")) + .contentType(MediaType.APPLICATION_JSON) + .header("Origin", "https://admin.icebang.site") + .header("Referer", "https://admin.icebang.site/") + .content(objectMapper.writeValueAsString(registerRequest))) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.success").value(false)) + .andExpect(jsonPath("$.status").value("BAD_REQUEST")); + } @Disabled @DisplayName("사용자 세션 체크") From 6576a4ba9fcf7375e2a4030d8839a84ed669fe1d Mon Sep 17 00:00:00 2001 From: can019 Date: Tue, 23 Sep 2025 15:42:06 +0900 Subject: [PATCH 3/7] =?UTF-8?q?test:=20Status=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../icebang/integration/tests/auth/AuthApiIntegrationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/user-service/src/test/java/site/icebang/integration/tests/auth/AuthApiIntegrationTest.java b/apps/user-service/src/test/java/site/icebang/integration/tests/auth/AuthApiIntegrationTest.java index d0cbd60a..e2e84b18 100644 --- a/apps/user-service/src/test/java/site/icebang/integration/tests/auth/AuthApiIntegrationTest.java +++ b/apps/user-service/src/test/java/site/icebang/integration/tests/auth/AuthApiIntegrationTest.java @@ -107,7 +107,7 @@ void registerSuccess() throws Exception { .content(objectMapper.writeValueAsString(registerRequest))) .andExpect(status().isCreated()) .andExpect(jsonPath("$.success").value(true)) - .andExpect(jsonPath("$.status").value("CREATED")) + .andExpect(jsonPath("$.status").value("OK")) .andExpect(jsonPath("$.message").value("OK")) .andExpect(jsonPath("$.data").isEmpty()) .andDo( From 3312a73e82812c6d60f98056e9ca29fe1d15f8f1 Mon Sep 17 00:00:00 2001 From: can019 Date: Tue, 23 Sep 2025 16:23:31 +0900 Subject: [PATCH 4/7] chore: v0.0.1 alpha -> beta --- apps/user-service/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/user-service/build.gradle b/apps/user-service/build.gradle index 4c5cb671..ff3f7e04 100644 --- a/apps/user-service/build.gradle +++ b/apps/user-service/build.gradle @@ -8,7 +8,7 @@ plugins { } group = 'site.icebang' -version = '0.0.1-alpha-SNAPSHOT' +version = '0.0.1-beta-STABLE' description = 'Ice bang - fast campus team4' java { From 2df9477e8bdc137732e1c7861674a5ae349380dc Mon Sep 17 00:00:00 2001 From: can019 Date: Tue, 23 Sep 2025 16:23:56 +0900 Subject: [PATCH 5/7] =?UTF-8?q?fix:=20Register=20api=EA=B0=80=20public=20a?= =?UTF-8?q?uth=EC=98=80=EB=8D=98=20=EB=B2=84=EA=B7=B8=20=ED=94=BD=EC=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../site/icebang/global/config/security/SecurityConfig.java | 2 ++ .../global/config/security/endpoints/SecurityEndpoints.java | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/user-service/src/main/java/site/icebang/global/config/security/SecurityConfig.java b/apps/user-service/src/main/java/site/icebang/global/config/security/SecurityConfig.java index 3543a8dd..514998e2 100644 --- a/apps/user-service/src/main/java/site/icebang/global/config/security/SecurityConfig.java +++ b/apps/user-service/src/main/java/site/icebang/global/config/security/SecurityConfig.java @@ -82,6 +82,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .permitAll() .requestMatchers("/v0/auth/check-session") .authenticated() + .requestMatchers(SecurityEndpoints.SUPER_ADMIN.getMatchers()) + .hasAnyRole("SUPER_ADMIN") .requestMatchers(SecurityEndpoints.DATA_ADMIN.getMatchers()) .hasRole("SUPER_ADMIN") // hasAuthority -> hasRole .requestMatchers(SecurityEndpoints.DATA_ENGINEER.getMatchers()) diff --git a/apps/user-service/src/main/java/site/icebang/global/config/security/endpoints/SecurityEndpoints.java b/apps/user-service/src/main/java/site/icebang/global/config/security/endpoints/SecurityEndpoints.java index e6e24243..98129d8b 100644 --- a/apps/user-service/src/main/java/site/icebang/global/config/security/endpoints/SecurityEndpoints.java +++ b/apps/user-service/src/main/java/site/icebang/global/config/security/endpoints/SecurityEndpoints.java @@ -11,7 +11,6 @@ public enum SecurityEndpoints { "/js/**", "/images/**", "/v0/organizations/**", - "/v0/auth/register", "/v0/check-execution-log-insert"), // 데이터 관리 관련 엔드포인트 @@ -27,7 +26,9 @@ public enum SecurityEndpoints { OPS("/api/scheduler/**", "/api/monitoring/**"), // 일반 사용자 엔드포인트 - USER("/user/**", "/profile/**", "/v0/auth/check-session", "/v0/workflows/**"); + USER("/user/**", "/profile/**", "/v0/auth/check-session", "/v0/workflows/**"), + + SUPER_ADMIN("/v0/auth/register"); private final String[] patterns; From e6e830b7de43f9e64bdc8f2a6018fd8afa4dbd68 Mon Sep 17 00:00:00 2001 From: can019 Date: Tue, 23 Sep 2025 16:24:28 +0900 Subject: [PATCH 6/7] =?UTF-8?q?fix:=20Bad=20request=20=EC=8B=9C=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20=EB=A9=94=EC=84=B8=EC=A7=80=EA=B0=80=20?= =?UTF-8?q?=EB=84=88=EB=AC=B4=20=EB=A7=8E=EC=9D=80=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EB=A5=BC=20=ED=8F=AC=ED=95=A8=ED=95=98=EB=8D=98=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit exception message가 모두 노출, 필요한 메세지만 출력하도록 변경 --- .../handler/exception/GlobalExceptionHandler.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/user-service/src/main/java/site/icebang/global/handler/exception/GlobalExceptionHandler.java b/apps/user-service/src/main/java/site/icebang/global/handler/exception/GlobalExceptionHandler.java index 8243acde..0711cf90 100644 --- a/apps/user-service/src/main/java/site/icebang/global/handler/exception/GlobalExceptionHandler.java +++ b/apps/user-service/src/main/java/site/icebang/global/handler/exception/GlobalExceptionHandler.java @@ -1,8 +1,11 @@ package site.icebang.global.handler.exception; +import java.util.stream.Collectors; + import org.springframework.http.HttpStatus; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.core.AuthenticationException; +import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; @@ -19,9 +22,13 @@ public class GlobalExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) - public ApiResponse handleValidation(MethodArgumentNotValidException ex) { - String detail = ex.getBindingResult().toString(); - return ApiResponse.error("Validation failed: " + detail, HttpStatus.BAD_REQUEST); + public ApiResponse handleValidation(MethodArgumentNotValidException ex) { + String errorMessage = + ex.getBindingResult().getFieldErrors().stream() + .map(FieldError::getDefaultMessage) + .collect(Collectors.joining(", ")); + + return ApiResponse.error("입력 값 검증 실패: " + errorMessage, HttpStatus.BAD_REQUEST); } @ExceptionHandler(Exception.class) From 9c5d06e988d0abcd80af4f35f2e7f15711d842a7 Mon Sep 17 00:00:00 2001 From: can019 Date: Tue, 23 Sep 2025 16:25:48 +0900 Subject: [PATCH 7/7] =?UTF-8?q?test:=20Register=20=EC=8B=A4=ED=8C=A8=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20rest=20api=20documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tests/auth/AuthApiIntegrationTest.java | 195 ++++++++++++++---- 1 file changed, 154 insertions(+), 41 deletions(-) diff --git a/apps/user-service/src/test/java/site/icebang/integration/tests/auth/AuthApiIntegrationTest.java b/apps/user-service/src/test/java/site/icebang/integration/tests/auth/AuthApiIntegrationTest.java index e2e84b18..95d0cfbd 100644 --- a/apps/user-service/src/test/java/site/icebang/integration/tests/auth/AuthApiIntegrationTest.java +++ b/apps/user-service/src/test/java/site/icebang/integration/tests/auth/AuthApiIntegrationTest.java @@ -11,12 +11,12 @@ import java.util.HashMap; import java.util.Map; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.http.*; import org.springframework.mock.web.MockHttpSession; import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.security.test.context.support.WithUserDetails; import org.springframework.test.context.jdbc.Sql; import org.springframework.transaction.annotation.Transactional; @@ -85,19 +85,19 @@ void loginSuccess() throws Exception { } @Test - @DisplayName("사용자 등록 성공") + @DisplayName("사용자 등록 실패 - 이메일 양식 오류") @WithUserDetails("admin@icebang.site") - void registerSuccess() throws Exception { + void registerFailureWhenInvalidEmail() throws Exception { // given Map registerRequest = new HashMap<>(); registerRequest.put("name", "홍길동"); - registerRequest.put("email", "hong@icebang.site"); + registerRequest.put("email", "invalid-email"); // 잘못된 이메일 형식 registerRequest.put("orgId", 1); registerRequest.put("deptId", 1); registerRequest.put("positionId", 1); - registerRequest.put("roleIds", Arrays.asList(1, 2)); + registerRequest.put("roleIds", Arrays.asList(1)); - // MockMvc로 REST Docs + OpenAPI 생성 + // when & then mockMvc .perform( post(getApiUrlForDocs("/v0/auth/register")) @@ -105,26 +105,24 @@ void registerSuccess() throws Exception { .header("Origin", "https://admin.icebang.site") .header("Referer", "https://admin.icebang.site/") .content(objectMapper.writeValueAsString(registerRequest))) - .andExpect(status().isCreated()) - .andExpect(jsonPath("$.success").value(true)) - .andExpect(jsonPath("$.status").value("OK")) - .andExpect(jsonPath("$.message").value("OK")) - .andExpect(jsonPath("$.data").isEmpty()) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.success").value(false)) + .andExpect(jsonPath("$.status").value("BAD_REQUEST")) .andDo( document( - "auth-register", + "auth-register-invalid-email", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), resource( ResourceSnippetParameters.builder() .tag("Authentication") - .summary("사용자 회원가입") - .description("새로운 사용자 계정을 생성합니다") + .summary("사용자 회원가입 실패 - 잘못된 이메일") + .description("잘못된 이메일 형식으로 인한 회원가입 실패") .requestFields( fieldWithPath("name").type(JsonFieldType.STRING).description("사용자명"), fieldWithPath("email") .type(JsonFieldType.STRING) - .description("사용자 이메일 주소"), + .description("잘못된 형식의 이메일 주소"), fieldWithPath("orgId").type(JsonFieldType.NUMBER).description("조직 ID"), fieldWithPath("deptId").type(JsonFieldType.NUMBER).description("부서 ID"), fieldWithPath("positionId") @@ -137,12 +135,10 @@ void registerSuccess() throws Exception { fieldWithPath("success") .type(JsonFieldType.BOOLEAN) .description("요청 성공 여부"), - fieldWithPath("data") - .type(JsonFieldType.NULL) - .description("응답 데이터 (회원가입 성공 시 null)"), + fieldWithPath("data").type(JsonFieldType.NULL).description("에러 시 null"), fieldWithPath("message") .type(JsonFieldType.STRING) - .description("응답 메시지"), + .description("에러 메시지"), fieldWithPath("status") .type(JsonFieldType.STRING) .description("HTTP 상태")) @@ -150,17 +146,64 @@ void registerSuccess() throws Exception { } @Test - @DisplayName("사용자 등록 실패 - 이메일 양식 오류") + @DisplayName("사용자 등록 실패 - 필수 필드 누락") @WithUserDetails("admin@icebang.site") - void registerFailureWhenInvalidEmail() throws Exception { + void registerFailureWhenMissingRequiredFields() throws Exception { + // given - 필수 필드 누락 + Map registerRequest = new HashMap<>(); + registerRequest.put("email", "test@icebang.site"); + // name, orgId, deptId, positionId, roleIds 누락 + + // when & then + mockMvc + .perform( + post(getApiUrlForDocs("/v0/auth/register")) + .contentType(MediaType.APPLICATION_JSON) + .header("Origin", "https://admin.icebang.site") + .header("Referer", "https://admin.icebang.site/") + .content(objectMapper.writeValueAsString(registerRequest))) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.success").value(false)) + .andExpect(jsonPath("$.status").value("BAD_REQUEST")) + .andDo( + document( + "auth-register-missing-fields", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Authentication") + .summary("사용자 회원가입 실패 - 필수 필드 누락") + .description("필수 필드 누락으로 인한 회원가입 실패") + .requestFields( + fieldWithPath("email") + .type(JsonFieldType.STRING) + .description("사용자 이메일 주소")) + .responseFields( + fieldWithPath("success") + .type(JsonFieldType.BOOLEAN) + .description("요청 성공 여부"), + fieldWithPath("data").type(JsonFieldType.NULL).description("에러 시 null"), + fieldWithPath("message") + .type(JsonFieldType.STRING) + .description("에러 메시지"), + fieldWithPath("status") + .type(JsonFieldType.STRING) + .description("HTTP 상태")) + .build()))); + } + + @Test + @DisplayName("사용자 등록 실패 - Authentication이 없는 경우") + void registerFailureWhenAuthenticationMissing() throws Exception { // given Map registerRequest = new HashMap<>(); registerRequest.put("name", "홍길동"); - registerRequest.put("email", "invalid-email"); // 잘못된 이메일 형식 + registerRequest.put("email", "hong@icebang.site"); registerRequest.put("orgId", 1); registerRequest.put("deptId", 1); registerRequest.put("positionId", 1); - registerRequest.put("roleIds", Arrays.asList(1)); + registerRequest.put("roleIds", Arrays.asList(1, 2)); // when & then mockMvc @@ -170,19 +213,60 @@ void registerFailureWhenInvalidEmail() throws Exception { .header("Origin", "https://admin.icebang.site") .header("Referer", "https://admin.icebang.site/") .content(objectMapper.writeValueAsString(registerRequest))) - .andExpect(status().isBadRequest()) + .andExpect(status().isUnauthorized()) .andExpect(jsonPath("$.success").value(false)) - .andExpect(jsonPath("$.status").value("BAD_REQUEST")); + .andExpect(jsonPath("$.status").value("UNAUTHORIZED")) + .andExpect(jsonPath("$.message").value("Authentication required")) + .andExpect(jsonPath("$.data").isEmpty()) + .andDo( + document( + "auth-register-unauthorized", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Authentication") + .summary("사용자 회원가입 실패 - 인증 없음") + .description("인증 정보가 없어서 회원가입 실패") + .requestFields( + fieldWithPath("name").type(JsonFieldType.STRING).description("사용자명"), + fieldWithPath("email") + .type(JsonFieldType.STRING) + .description("사용자 이메일 주소"), + fieldWithPath("orgId").type(JsonFieldType.NUMBER).description("조직 ID"), + fieldWithPath("deptId").type(JsonFieldType.NUMBER).description("부서 ID"), + fieldWithPath("positionId") + .type(JsonFieldType.NUMBER) + .description("직책 ID"), + fieldWithPath("roleIds") + .type(JsonFieldType.ARRAY) + .description("역할 ID 목록")) + .responseFields( + fieldWithPath("success") + .type(JsonFieldType.BOOLEAN) + .description("요청 성공 여부"), + fieldWithPath("data").type(JsonFieldType.NULL).description("에러 시 null"), + fieldWithPath("message") + .type(JsonFieldType.STRING) + .description("인증 에러 메시지"), + fieldWithPath("status") + .type(JsonFieldType.STRING) + .description("HTTP 상태")) + .build()))); } @Test - @DisplayName("사용자 등록 실패 - 필수 필드 누락") - @WithUserDetails("admin@icebang.site") - void registerFailureWhenMissingRequiredFields() throws Exception { - // given - 필수 필드 누락 + @DisplayName("사용자 등록 실패 - Permission이 없는 경우") + @WithMockUser("content.choi@icebang.site") + void registerFailureWhenNoPermissionProvided() throws Exception { + // given Map registerRequest = new HashMap<>(); - registerRequest.put("email", "test@icebang.site"); - // name, orgId, deptId, positionId, roleIds 누락 + registerRequest.put("name", "홍길동"); + registerRequest.put("email", "hong@icebang.site"); + registerRequest.put("orgId", 1); + registerRequest.put("deptId", 1); + registerRequest.put("positionId", 1); + registerRequest.put("roleIds", Arrays.asList(1, 2)); // when & then mockMvc @@ -192,19 +276,48 @@ void registerFailureWhenMissingRequiredFields() throws Exception { .header("Origin", "https://admin.icebang.site") .header("Referer", "https://admin.icebang.site/") .content(objectMapper.writeValueAsString(registerRequest))) - .andExpect(status().isBadRequest()) + .andExpect(status().isForbidden()) .andExpect(jsonPath("$.success").value(false)) - .andExpect(jsonPath("$.status").value("BAD_REQUEST")); + .andExpect(jsonPath("$.status").value("FORBIDDEN")) + .andExpect(jsonPath("$.message").value("Access denied")) + .andExpect(jsonPath("$.data").isEmpty()) + .andDo( + document( + "auth-register-forbidden", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("Authentication") + .summary("사용자 회원가입 실패 - 권한 부족") + .description("적절한 권한이 없어서 회원가입 실패") + .requestFields( + fieldWithPath("name").type(JsonFieldType.STRING).description("사용자명"), + fieldWithPath("email") + .type(JsonFieldType.STRING) + .description("사용자 이메일 주소"), + fieldWithPath("orgId").type(JsonFieldType.NUMBER).description("조직 ID"), + fieldWithPath("deptId").type(JsonFieldType.NUMBER).description("부서 ID"), + fieldWithPath("positionId") + .type(JsonFieldType.NUMBER) + .description("직책 ID"), + fieldWithPath("roleIds") + .type(JsonFieldType.ARRAY) + .description("역할 ID 목록")) + .responseFields( + fieldWithPath("success") + .type(JsonFieldType.BOOLEAN) + .description("요청 성공 여부"), + fieldWithPath("data").type(JsonFieldType.NULL).description("에러 시 null"), + fieldWithPath("message") + .type(JsonFieldType.STRING) + .description("권한 에러 메시지"), + fieldWithPath("status") + .type(JsonFieldType.STRING) + .description("HTTP 상태")) + .build()))); } - @Disabled - @DisplayName("사용자 세션 체크") - void checkSession() throws Exception {} - - @Disabled - @DisplayName("사용자 권한 요청") - void userPermission() throws Exception {} - @Test @DisplayName("사용자 로그아웃 성공") void logoutSuccess() throws Exception {