Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ExtendedErrorAttributes #270

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,6 @@ jacocoTestReport {
fileTree(dir: it, exclude: [\
'edu/kit/datamanager/pit/configuration/**', \
'edu/kit/datamanager/pit/web/converter/**', \
'edu/kit/datamanager/pit/web/ExtendedErrorAttributes**', \
'edu/kit/datamanager/pit/web/UncontrolledExceptionHandler**', \
'edu/kit/datamanager/pit/common/**', \
'edu/kit/datamanager/pit/Application*'
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/edu/kit/datamanager/pit/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import edu.kit.datamanager.pit.pitservice.impl.TypingService;
import edu.kit.datamanager.pit.typeregistry.ITypeRegistry;
import edu.kit.datamanager.pit.typeregistry.impl.TypeRegistry;
import edu.kit.datamanager.pit.web.ExtendedErrorAttributes;
import edu.kit.datamanager.pit.web.converter.SimplePidRecordConverter;
import edu.kit.datamanager.security.filter.KeycloakJwtProperties;

Expand Down Expand Up @@ -100,6 +101,11 @@ public Logger logger(InjectionPoint injectionPoint) {
return LoggerFactory.getLogger(targetClass.getCanonicalName());
}

@Bean
public ExtendedErrorAttributes errorAttributes(ObjectMapper objectMapper) {
return new ExtendedErrorAttributes(objectMapper);
}

@Bean
public ITypeRegistry typeRegistry() {
return new TypeRegistry();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@

import edu.kit.datamanager.pit.domain.PIDRecord;

import java.io.Serial;

/**
* Indicates that a PID was given which could not be resolved to answer the
* request properly.
*/
public class RecordValidationException extends ResponseStatusException {

private static final String VALIDATION_OF_RECORD = "Validation of record ";
private static final long serialVersionUID = 1L;
@Serial
private static final long serialVersionUID = -7287999233733933282L;
private static final HttpStatus HTTP_STATUS = HttpStatus.BAD_REQUEST;

// For cases in which the PID record shold be appended to the error response.
private final transient PIDRecord pidRecord;
// For cases in which the PID record should be appended to the error response.
private final PIDRecord pidRecord;

public RecordValidationException(PIDRecord pidRecord) {
super(HTTP_STATUS, VALIDATION_OF_RECORD + pidRecord.getPid() + " failed.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,29 @@

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;

import com.fasterxml.jackson.databind.ObjectMapper;

import edu.kit.datamanager.pit.common.RecordValidationException;

@Component
public class ExtendedErrorAttributes extends DefaultErrorAttributes {

@Autowired(required = true)
ObjectMapper objectMapperBean;

public ExtendedErrorAttributes(ObjectMapper objectMapperBean) {
this.objectMapperBean = objectMapperBean;
}

@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
final Map<String, Object> errorAttributes =
super.getErrorAttributes(webRequest, options);

final Throwable error = super.getError(webRequest);
if (error instanceof RecordValidationException) {
final RecordValidationException validationError = (RecordValidationException) error;
if (error instanceof RecordValidationException validationError) {
try {
errorAttributes.put("pid-record", objectMapperBean.writeValueAsString(validationError.getPidRecord()));
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package edu.kit.datamanager.pit.web;

import java.util.Map;

import edu.kit.datamanager.pit.common.RecordValidationException;
import edu.kit.datamanager.pit.domain.PIDRecord;
import jakarta.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.Test;
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.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.ServletWebRequest;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@ActiveProfiles("test")
public class ExtendedErrorAttributesTest {

@Autowired
private TestRestTemplate restTemplate;

@Autowired
private WebApplicationContext webApplicationContext;

@Autowired
private ExtendedErrorAttributes errorAttributes;

@Test
public void testPidRecordPresence() {
// Create a mock request to pass to the error attributes
HttpServletRequest request = new MockHttpServletRequest();
WebRequest webRequest = new ServletWebRequest(request);

// Simulate an exception to be handled by the error attributes
request.setAttribute("jakarta.servlet.error.exception", new RecordValidationException(
new PIDRecord().withPID("asdfg"),
"Validation failed"
));

// Get the error attributes
Map<String, Object> attributes = errorAttributes.getErrorAttributes(webRequest, ErrorAttributeOptions.defaults());

// Check if the custom attribute is present
assertTrue(attributes.containsKey("pid-record"));
}

@Test
public void testBeanRegistration() {
// Check if the ExtendedErrorAttributes bean is registered
ExtendedErrorAttributes extendedErrorAttributes = webApplicationContext.getBean(ExtendedErrorAttributes.class);
assertNotNull(extendedErrorAttributes, "ExtendedErrorAttributes bean should be registered");
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package edu.kit.datamanager.pit.web;

import static org.junit.jupiter.api.Assertions.assertTrue;

import com.fasterxml.jackson.databind.ObjectMapper;
import edu.kit.datamanager.pit.domain.PIDRecord;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
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.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
Expand All @@ -18,7 +21,9 @@
import edu.kit.datamanager.pit.SpringTestHelper;
import edu.kit.datamanager.pit.pitservice.impl.NoValidationStrategy;

import static org.junit.jupiter.api.Assertions.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;

// Might be needed for WebApp testing according to https://www.baeldung.com/integration-testing-in-spring
//@WebAppConfiguration
Expand Down Expand Up @@ -46,6 +51,25 @@ void setup() throws Exception {
.assertNoBeanInstanceOf(NoValidationStrategy.class);
}

@Test
void testPidRecordInErrorJson() throws Exception {
PIDRecord r = new PIDRecord();
r.addEntry("21.T11148/076759916209e5d62bd5", "for Testing", "21.T11148/301c6f04763a16f0f72a");
MvcResult result = this.mockMvc
.perform(
post("/api/v1/pit/pid/")
.contentType(MediaType.APPLICATION_JSON)
.characterEncoding("utf-8")
.content(new ObjectMapper().writeValueAsString(r))
.accept(MediaType.ALL)
)
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isBadRequest())
.andExpect(MockMvcResultMatchers.jsonPath("$.pid-record", Matchers.containsString("for Testing")))
.andReturn();
assertFalse(result.getResponse().getContentAsString().isEmpty());
}

/**
* Tests if the swagger ui and openapi definition is accessible.
*
Expand Down
Loading