Map unexpected error to response 93/60493/3
authortalig <talig@amdocs.com>
Wed, 15 Aug 2018 10:32:41 +0000 (13:32 +0300)
committertalig <talig@amdocs.com>
Wed, 15 Aug 2018 10:32:41 +0000 (13:32 +0300)
Change-Id: I84293aa040b736670885f01d625862cf41e359d2
Issue-ID: SDC-1647
Signed-off-by: talig <talig@amdocs.com>
workflow-bdd/features/VersionState.feature
workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/ExceptionsHandler.java
workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/types/UnexpectedErrorResponse.java [new file with mode: 0644]
workflow-designer-be/src/test/java/org/onap/sdc/workflow/api/ExceptionsHandlerTest.java [new file with mode: 0644]

index 1bb72ab..09e93a7 100644 (file)
@@ -51,5 +51,5 @@ Feature: Workflow Version State
     When I want to update for path "/workflows/{item.id}/versions/{item.versionId}" with the input data from the context
 
   Scenario: Create second version based on non CERTIFIED one - invalid
-    Then I want the following to fail with response status code 403
+    Then I want the following to fail with response status code 422
     When I want to create for path "/workflows/{item.id}/versions?baseVersionId={item.versionId}" with the input data from the context
\ No newline at end of file
index 5e6fc07..f46d19b 100644 (file)
 package org.onap.sdc.workflow.api;
 
 import static org.springframework.http.HttpStatus.BAD_REQUEST;
-import static org.springframework.http.HttpStatus.FORBIDDEN;
 import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
 import static org.springframework.http.HttpStatus.NOT_FOUND;
 import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;
 
+import java.util.function.Function;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.commons.text.RandomStringGenerator;
 import org.onap.sdc.workflow.api.types.ErrorResponse;
+import org.onap.sdc.workflow.api.types.UnexpectedErrorResponse;
 import org.onap.sdc.workflow.services.exceptions.EntityNotFoundException;
 import org.onap.sdc.workflow.services.exceptions.InvalidArtifactException;
 import org.onap.sdc.workflow.services.exceptions.UniqueValueViolationException;
@@ -30,6 +33,8 @@ import org.onap.sdc.workflow.services.exceptions.VersionCreationException;
 import org.onap.sdc.workflow.services.exceptions.VersionModificationException;
 import org.onap.sdc.workflow.services.exceptions.VersionStateModificationException;
 import org.onap.sdc.workflow.services.exceptions.VersionStatusModificationException;
+import org.openecomp.sdc.logging.api.Logger;
+import org.openecomp.sdc.logging.api.LoggerFactory;
 import org.springframework.context.support.DefaultMessageSourceResolvable;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
@@ -46,44 +51,63 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep
 @RestController
 public class ExceptionsHandler extends ResponseEntityExceptionHandler {
 
-    @ExceptionHandler(EntityNotFoundException.class)
-    public final ResponseEntity<ErrorResponse> handleNotFoundException(Exception exception) {
-        return new ResponseEntity<>(new ErrorResponse(exception.getMessage()), NOT_FOUND);
-    }
+    private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionsHandler.class);
+    private static final String LOG_MSG = "Exception was mapped to {} response";
+    private static final String UNEXPECTED_ERROR_MSG = "Something bad happened. Please contact support with code %s";
+    private static final RandomStringGenerator CODE_GENERATOR =
+            new RandomStringGenerator.Builder().withinRange('A', 'Z').build();
+    private static final int CODE_LENGTH = 8;
 
-    @ExceptionHandler({InvalidArtifactException.class, VersionModificationException.class,
-            VersionStateModificationException.class, VersionStatusModificationException.class,
-            UniqueValueViolationException.class})
-    public final ResponseEntity<ErrorResponse> handleUnprocessableEntityException(Exception exception) {
-        return new ResponseEntity<>(new ErrorResponse(exception.getMessage()), UNPROCESSABLE_ENTITY);
-    }
+    private static final Function<Exception, UnexpectedErrorResponse> UNEXPECTED_EXCEPTION_MAPPER =
+            isDevInfoDisabled()
+                    ? e -> new UnexpectedErrorResponse(getUnexpectedErrorMessage())
+                    : e -> new UnexpectedErrorResponse(getUnexpectedErrorMessage(), ExceptionUtils.getStackTrace(e));
 
-    @ExceptionHandler(VersionCreationException.class)
-    public final ResponseEntity<ErrorResponse> handleVersioningErrorException(VersionCreationException exception) {
-        return new ResponseEntity<>(new ErrorResponse(exception.getMessage()), FORBIDDEN);
-    }
-
-    @ExceptionHandler(Exception.class)
-    public final ResponseEntity<ErrorResponse> handleUnexpectedException(Exception exception) {
-        return new ResponseEntity<>(new ErrorResponse(exception.getMessage()), INTERNAL_SERVER_ERROR);
-    }
-
-    //For missing header exceptions
     @Override
     public ResponseEntity<Object> handleServletRequestBindingException(ServletRequestBindingException ex,
             HttpHeaders headers, HttpStatus status, WebRequest request) {
+        //For missing header exceptions
+        LOGGER.debug(LOG_MSG, BAD_REQUEST, ex);
         return new ResponseEntity<>(new ErrorResponse(ex.getMessage()), BAD_REQUEST);
     }
 
     @Override
     protected final ResponseEntity<Object> handleMethodArgumentNotValid(final MethodArgumentNotValidException exception,
-            final HttpHeaders headers,
-            final HttpStatus status,
-            final WebRequest request) {
-
+            final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
+        LOGGER.debug(LOG_MSG, BAD_REQUEST, exception);
         String errorMsg = exception.getBindingResult().getFieldErrors().stream()
                                   .map(DefaultMessageSourceResolvable::getDefaultMessage).findFirst()
                                   .orElse(exception.getMessage());
         return new ResponseEntity<>(new ErrorResponse(errorMsg), BAD_REQUEST);
     }
+
+    @ExceptionHandler(EntityNotFoundException.class)
+    public final ResponseEntity<ErrorResponse> handleNotFoundException(Exception exception) {
+        LOGGER.debug(LOG_MSG, NOT_FOUND, exception);
+        return new ResponseEntity<>(new ErrorResponse(exception.getMessage()), NOT_FOUND);
+    }
+
+    @ExceptionHandler(
+            {InvalidArtifactException.class, VersionCreationException.class, VersionModificationException.class,
+                    VersionStateModificationException.class, VersionStatusModificationException.class,
+                    UniqueValueViolationException.class})
+    public final ResponseEntity<ErrorResponse> handleUnprocessableEntityException(Exception exception) {
+        LOGGER.debug(LOG_MSG, UNPROCESSABLE_ENTITY, exception);
+        return new ResponseEntity<>(new ErrorResponse(exception.getMessage()), UNPROCESSABLE_ENTITY);
+    }
+
+    @ExceptionHandler(Exception.class)
+    public final ResponseEntity<UnexpectedErrorResponse> handleUnexpectedException(Exception exception) {
+        UnexpectedErrorResponse response = UNEXPECTED_EXCEPTION_MAPPER.apply(exception);
+        LOGGER.error(response.getMessage(), exception);
+        return new ResponseEntity<>(response, INTERNAL_SERVER_ERROR);
+    }
+
+    private static boolean isDevInfoDisabled() {
+        return Boolean.FALSE.toString().equalsIgnoreCase(System.getProperty("errors.includeDevInfo"));
+    }
+
+    private static String getUnexpectedErrorMessage() {
+        return String.format(UNEXPECTED_ERROR_MSG, CODE_GENERATOR.generate(CODE_LENGTH));
+    }
 }
diff --git a/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/types/UnexpectedErrorResponse.java b/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/types/UnexpectedErrorResponse.java
new file mode 100644 (file)
index 0000000..fbc5ab3
--- /dev/null
@@ -0,0 +1,18 @@
+package org.onap.sdc.workflow.api.types;
+
+import lombok.Getter;
+
+@Getter
+public class UnexpectedErrorResponse extends ErrorResponse {
+
+    private String devInfo;
+
+    public UnexpectedErrorResponse(String message) {
+        super(message);
+    }
+
+    public UnexpectedErrorResponse(String message, String devInfo) {
+        super(message);
+        this.devInfo = devInfo;
+    }
+}
diff --git a/workflow-designer-be/src/test/java/org/onap/sdc/workflow/api/ExceptionsHandlerTest.java b/workflow-designer-be/src/test/java/org/onap/sdc/workflow/api/ExceptionsHandlerTest.java
new file mode 100644 (file)
index 0000000..e4008bb
--- /dev/null
@@ -0,0 +1,54 @@
+package org.onap.sdc.workflow.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
+import static org.springframework.http.HttpStatus.NOT_FOUND;
+import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.onap.sdc.workflow.api.types.ErrorResponse;
+import org.onap.sdc.workflow.api.types.UnexpectedErrorResponse;
+import org.onap.sdc.workflow.services.exceptions.EntityNotFoundException;
+import org.onap.sdc.workflow.services.exceptions.VersionModificationException;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+public class ExceptionsHandlerTest {
+
+    @InjectMocks
+    private ExceptionsHandler exceptionsHandler;
+
+    @Test
+    public void handleNotFoundException() {
+        EntityNotFoundException exception = new EntityNotFoundException("message");
+        ResponseEntity<ErrorResponse> response = exceptionsHandler.handleNotFoundException(exception);
+
+        assertEquals(NOT_FOUND, response.getStatusCode());
+        assertEquals(exception.getMessage(), response.getBody().getMessage());
+    }
+
+    @Test
+    public void handleUnprocessableEntityException() {
+        VersionModificationException exception = new VersionModificationException("1", "2");
+        ResponseEntity<ErrorResponse> response = exceptionsHandler.handleUnprocessableEntityException(exception);
+
+        assertEquals(UNPROCESSABLE_ENTITY, response.getStatusCode());
+        assertEquals(exception.getMessage(), response.getBody().getMessage());
+    }
+
+    @Test
+    public void handleUnexpectedException() {
+        Exception exception = new Exception("message");
+        ResponseEntity<UnexpectedErrorResponse> response = exceptionsHandler.handleUnexpectedException(exception);
+
+        assertEquals(INTERNAL_SERVER_ERROR, response.getStatusCode());
+        assertNotNull(response.getBody().getMessage());
+        assertFalse(response.getBody().getMessage().contains(exception.getMessage()));
+        assertNotNull(response.getBody().getDevInfo());
+    }
+}
\ No newline at end of file