diff --git a/ordinis-app/src/test/java/cloud/nstart/terravault/ordinis/app/e2e/SmokeE2ETest.java b/ordinis-app/src/test/java/cloud/nstart/terravault/ordinis/app/e2e/SmokeE2ETest.java index 13f71fd..4669ce8 100644 --- a/ordinis-app/src/test/java/cloud/nstart/terravault/ordinis/app/e2e/SmokeE2ETest.java +++ b/ordinis-app/src/test/java/cloud/nstart/terravault/ordinis/app/e2e/SmokeE2ETest.java @@ -127,4 +127,33 @@ class SmokeE2ETest { assertThat(newEntries).isNotEmpty(); assertThat(newEntries.get(0).getBusinessKey()).isEqualTo(businessKey); } + + /** + * Regression: unrouted path должен возвращать 404 not_found, не 500 + * internal_error. + * + *
До MR-fix: NoResourceFoundException попадал в generic Exception handler + * в GlobalExceptionHandler → 500. Симптомы на prod включали: + *
Покрывает оба пути: путь похожий на API ({@code /api/v1/notexist}) и + * generic non-API ({@code /random/path}). + */ + @Test + void unknownPath_returns404WithNotFoundCode() throws Exception { + mvc.perform(get("/api/v1/this-endpoint-does-not-exist")) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.status").value(404)) + .andExpect(jsonPath("$.code").value("not_found")); + + mvc.perform(get("/swagger-ui/index.html")) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.status").value(404)) + .andExpect(jsonPath("$.code").value("not_found")); + } } diff --git a/ordinis-rest-api/src/main/java/cloud/nstart/terravault/ordinis/restapi/error/GlobalExceptionHandler.java b/ordinis-rest-api/src/main/java/cloud/nstart/terravault/ordinis/restapi/error/GlobalExceptionHandler.java index 9cb6373..1c3ebc6 100644 --- a/ordinis-rest-api/src/main/java/cloud/nstart/terravault/ordinis/restapi/error/GlobalExceptionHandler.java +++ b/ordinis-rest-api/src/main/java/cloud/nstart/terravault/ordinis/restapi/error/GlobalExceptionHandler.java @@ -11,6 +11,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.NoHandlerFoundException; +import org.springframework.web.servlet.resource.NoResourceFoundException; import java.time.format.DateTimeParseException; @@ -73,6 +75,43 @@ public class GlobalExceptionHandler { return ResponseEntity.badRequest().body(body); } + /** + * Path не имеет зарегистрированного controller'а ИЛИ static resource'а. + * + *
Spring MVC throws: + *
До этого handler'а оба exception'а попадали в generic {@link Exception} + * catch ниже → возвращали 500 internal_error. Эффекты: + *
Лог уровня DEBUG (не WARN/ERROR) — это ожидаемый 404, не аномалия.
+ */
+ @ExceptionHandler({NoResourceFoundException.class, NoHandlerFoundException.class})
+ public ResponseEntity