Skip to content
Snippets Groups Projects
Commit 93d997af authored by OZGCloud's avatar OZGCloud
Browse files

Merge pull request 'OZG-4717-BasicAnwendungsSetupFix' (#23) from...

Merge pull request 'OZG-4717-BasicAnwendungsSetupFix' (#23) from OZG-4717-BasicAnwendungsSetupFix into master

Reviewed-on: https://git.ozg-sh.de/ozgcloud-app/administration/pulls/23
parents 16e1a9a3 c6c6b157
Branches
Tags
No related merge requests found
Showing
with 96 additions and 41 deletions
......@@ -28,12 +28,10 @@ import org.springframework.hateoas.server.RepresentationModelAssembler;
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
import org.springframework.stereotype.Component;
import io.micrometer.common.lang.NonNullApi;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
@NonNullApi
public class RootModelAssembler implements RepresentationModelAssembler<Root, EntityModel<Root>> {
static final String REL_CONFIGURATION = "configuration";
......
......@@ -19,7 +19,7 @@
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.admin.errorhandling;
package de.ozgcloud.admin.common.errorhandling;
import java.util.Map;
......@@ -36,7 +36,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep
import de.ozgcloud.common.errorhandling.TechnicalException;
@RestControllerAdvice
public class AdminExceptionHandler extends ResponseEntityExceptionHandler {
public class ExceptionController extends ResponseEntityExceptionHandler {
static final Map<Class<? extends Exception>, HttpStatus> STATUS_BY_EXCEPTION = Map.of(
RuntimeException.class, HttpStatus.INTERNAL_SERVER_ERROR,
......
......@@ -19,7 +19,7 @@
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.admin.errorhandling;
package de.ozgcloud.admin.common.errorhandling;
import java.io.Serial;
import java.util.UUID;
......
......@@ -14,7 +14,7 @@ import lombok.RequiredArgsConstructor;
@RequestMapping(FrontendEnvironmentController.PATH)
public class FrontendEnvironmentController {
static final String PATH = "/api/environment"; // NOSONAR
static final String PATH = "/api/frontendEnvironment"; // NOSONAR
private final ProductionProperties environmentProperties;
......
......@@ -53,7 +53,7 @@ public class SecurityConfiguration {
http.exceptionHandling(eh -> eh.authenticationEntryPoint(authenticationEntryPoint));
http.authorizeHttpRequests(requests -> requests
.requestMatchers(HttpMethod.GET, "/api/environment").permitAll()
.requestMatchers(HttpMethod.GET, "/api/frontendEnvironment").permitAll()
.requestMatchers("/api").authenticated()
.requestMatchers("/api/**").authenticated()
.requestMatchers("/actuator").permitAll()
......
package de.ozgcloud.admin.errorhandling;
package de.ozgcloud.admin.common.errorhandling;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import java.util.Set;
import java.util.stream.Stream;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.constraints.NotEmpty;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
......@@ -23,12 +30,14 @@ import org.springframework.test.web.servlet.ResultActions;
import de.ozgcloud.admin.RootController;
import de.ozgcloud.admin.RootModelAssembler;
import de.ozgcloud.common.test.ITCase;
import lombok.Builder;
import lombok.Getter;
import lombok.SneakyThrows;
@ITCase
@AutoConfigureMockMvc
@WithMockUser
public class AdminExceptionHandlerITCase {
class ExceptionControllerITCase {
@Autowired
private MockMvc mockMvc;
......@@ -46,23 +55,9 @@ public class AdminExceptionHandlerITCase {
var result = performGet();
System.out.println(result.andReturn().getResponse().getContentAsString());
result.andExpect(status().is(expectedStatus.value()));
}
@Test
@SneakyThrows
void shouldHandleRuntimeExceptionExceptionWithStatus() {
when(modelAssembler.toModel(any())).thenThrow(new RuntimeException("Message"));
var result = performGet();
System.out.println(result.andReturn().getResponse().getContentAsString());
result.andExpect(status().isInternalServerError());
}
@ParameterizedTest
@MethodSource("exceptionAndExpectedStatus")
@SneakyThrows
......@@ -75,13 +70,42 @@ public class AdminExceptionHandlerITCase {
}
private static Stream<Arguments> exceptionAndExpectedStatus() {
return AdminExceptionHandler.STATUS_BY_EXCEPTION.entrySet().stream().map(kv -> Arguments.of(kv.getKey(), kv.getValue()));
return ExceptionController.STATUS_BY_EXCEPTION.entrySet().stream().map(kv -> Arguments.of(kv.getKey(), kv.getValue()));
}
}
@Nested
class TestConstraintViolationException {
@Test
@SneakyThrows
private ResultActions performGet() {
return mockMvc.perform(get(RootController.PATH));
void shouldHaveValidationMessage() {
when(modelAssembler.toModel(any())).thenAnswer((a) -> {
throw new ConstraintViolationException(getConstraintViolations());
});
var result = performGet();
result.andExpect(jsonPath("$.detail").value("string: Empty field"));
}
private Set<ConstraintViolation<ValidatedClass>> getConstraintViolations() {
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
return validator.validate(ValidatedClass.builder().build());
}
@Getter
@Builder
private static class ValidatedClass {
@NotEmpty(message = "Empty field")
private String string;
}
}
@SneakyThrows
private ResultActions performGet() {
return mockMvc.perform(get(RootController.PATH));
}
}
......@@ -19,9 +19,9 @@
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.admin.errorhandling;
package de.ozgcloud.admin.common.errorhandling;
import static de.ozgcloud.admin.errorhandling.AdminExceptionHandler.*;
import static de.ozgcloud.admin.common.errorhandling.ExceptionController.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
......@@ -41,7 +41,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import lombok.SneakyThrows;
class AdminExceptionHandlerTest {
class ExceptionControllerTest {
private MockMvc mockMvc;
......@@ -49,7 +49,7 @@ class AdminExceptionHandlerTest {
void setup() {
mockMvc = MockMvcBuilders
.standaloneSetup(new TestErrorController())
.setControllerAdvice(new AdminExceptionHandler()).build();
.setControllerAdvice(new ExceptionController()).build();
}
@DisplayName("Error handler")
......@@ -74,13 +74,49 @@ class AdminExceptionHandlerTest {
result.andExpect(jsonPath("$.status").value(expectedStatus.value()));
}
@ParameterizedTest
@MethodSource("exceptionAndExpectedStatus")
@SneakyThrows
void shouldRespondWithTitler(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) {
var result = doPerformWithError(exceptionClass);
result.andExpect(jsonPath("$.title").exists());
}
@ParameterizedTest
@MethodSource("exceptionAndExpectedStatus")
@SneakyThrows
void shouldRespondWithDetail(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) {
var result = doPerformWithError(exceptionClass);
result.andExpect(jsonPath("$.detail").exists());
}
@ParameterizedTest
@MethodSource("exceptionAndExpectedStatus")
@SneakyThrows
void shouldRespondWithInstance(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) {
var result = doPerformWithError(exceptionClass);
result.andExpect(jsonPath("$.instance").exists());
}
@ParameterizedTest
@MethodSource("exceptionAndExpectedStatus")
@SneakyThrows
void shouldRespondWithType(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) {
var result = doPerformWithError(exceptionClass);
result.andExpect(jsonPath("$.type").exists());
}
private static Stream<Arguments> exceptionAndExpectedStatus() {
return STATUS_BY_EXCEPTION.entrySet().stream().map(kv -> Arguments.of(kv.getKey(), kv.getValue()));
}
@SneakyThrows
private ResultActions doPerformWithError(Class<? extends Exception> exceptionClass) {
return mockMvc.perform(get("/test-error").param("errorClassName", exceptionClass.getName()));
return mockMvc.perform(get("/api/test-error").param("errorClassName", exceptionClass.getName()));
}
}
......
......@@ -19,7 +19,7 @@
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.admin.errorhandling;
package de.ozgcloud.admin.common.errorhandling;
import java.util.Collections;
import java.util.Map;
......@@ -34,11 +34,9 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import de.ozgcloud.common.errorhandling.TechnicalException;
import io.micrometer.common.lang.NonNullApi;
@RestController
@RequestMapping("/test-error")
@NonNullApi
@RequestMapping("/api/test-error")
class TestErrorController {
@FunctionalInterface
......@@ -54,13 +52,12 @@ class TestErrorController {
ConstraintViolationException.class, () -> new ConstraintViolationException(ERROR_MESSAGE, Collections.emptySet()),
ResourceNotFoundException.class, () -> new ResourceNotFoundException(ERROR_MESSAGE),
FunctionalException.class, () -> new FunctionalException(() -> ERROR_MESSAGE),
TechnicalException.class, () -> new TechnicalException(ERROR_MESSAGE)
);
TechnicalException.class, () -> new TechnicalException(ERROR_MESSAGE));
@GetMapping
String throwException(@RequestParam String errorClassName) throws Exception {
throw EXCEPTION_PRODUCER.get(
Class.forName(errorClassName)
).produceException();
Class.forName(errorClassName)).produceException();
}
}
......@@ -67,7 +67,7 @@ class SecurityConfigurationITCase {
@SneakyThrows
@ParameterizedTest
@ValueSource(strings = {
"/api/environment",
"/api/frontendEnvironment",
"/configserver/name/profile"
})
void shouldAllow(String path) {
......@@ -145,7 +145,7 @@ class SecurityConfigurationITCase {
@SneakyThrows
@ParameterizedTest
@ValueSource(strings = {
"/api/environment",
"/api/frontendEnvironment",
"/configserver/name/profile",
"/api", "/api/configuration", "/api/configuration/param",
})
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment