diff --git a/service/src/main/java/com/ericsson/eiffel/remrem/generate/constants/RemremGenerateServiceConstants.java b/service/src/main/java/com/ericsson/eiffel/remrem/generate/constants/RemremGenerateServiceConstants.java index 04136b5..3c7a386 100644 --- a/service/src/main/java/com/ericsson/eiffel/remrem/generate/constants/RemremGenerateServiceConstants.java +++ b/service/src/main/java/com/ericsson/eiffel/remrem/generate/constants/RemremGenerateServiceConstants.java @@ -25,6 +25,9 @@ public final class RemremGenerateServiceConstants { public static final String NO_TEMPLATE_ERROR = "{\"status_code\": 404, \"result\": \"FAIL\", " + "\"message\":\"Requested template is not available\"}"; + public static final String TEMPLATE_ERROR = "{\"status_code\": 400, \"result\": \"FAIL\", " + + "\"message\":\"Template is not correct format or something is missing in the template, please check\"}"; + public static final String INTERNAL_SERVER_ERROR = "{\"status_code\": 500, \"result\": \"FAIL\", " + "\"message\":\"Internal server error\"}"; @@ -54,4 +57,14 @@ public final class RemremGenerateServiceConstants { public static final String LenientValidation = "okToLeaveOutInvalidOptionalFields true will remove the optional " + "event fields from the input event data that does not validate successfully, " + "and add those removed field information into customData/remremGenerateFailures"; + + public static final String JSON_STATUS_CODE = "status code"; + + public static final String JSON_STATUS_RESULT = "result"; + + public static final String META = "meta"; + + public static final String JSON_ERROR_STATUS = "FAIL"; + + public static final String JSON_FATAL_STATUS = "FATAL"; } diff --git a/service/src/main/java/com/ericsson/eiffel/remrem/generate/controller/RemremGenerateController.java b/service/src/main/java/com/ericsson/eiffel/remrem/generate/controller/RemremGenerateController.java index 9ee5214..5a1794a 100644 --- a/service/src/main/java/com/ericsson/eiffel/remrem/generate/controller/RemremGenerateController.java +++ b/service/src/main/java/com/ericsson/eiffel/remrem/generate/controller/RemremGenerateController.java @@ -18,12 +18,12 @@ import com.ericsson.eiffel.remrem.generate.constants.RemremGenerateServiceConstants; import com.ericsson.eiffel.remrem.generate.exception.REMGenerateException; import com.ericsson.eiffel.remrem.protocol.MsgService; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.*; import ch.qos.logback.classic.Logger; import io.swagger.annotations.*; @@ -46,14 +46,13 @@ import springfox.documentation.annotations.ApiIgnore; -import java.io.BufferedReader; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStreamReader; +import java.io.*; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import static com.ericsson.eiffel.remrem.generate.constants.RemremGenerateServiceConstants.*; + @RestController @RequestMapping("/*") @Api(value = "REMReM Generate Service", description = "REST API for generating Eiffel messages") @@ -78,10 +77,10 @@ public class RemremGenerateController { private boolean lenientValidationEnabledToUsers; public void setLenientValidationEnabledToUsers(boolean lenientValidationEnabledToUsers) { - this.lenientValidationEnabledToUsers = lenientValidationEnabledToUsers; - } + this.lenientValidationEnabledToUsers = lenientValidationEnabledToUsers; + } - private static RestTemplate restTemplate = new RestTemplate(); + private static RestTemplate restTemplate = new RestTemplate(); public void setRestTemplate(RestTemplate restTemplate) { this.restTemplate = restTemplate; @@ -89,73 +88,230 @@ public void setRestTemplate(RestTemplate restTemplate) { /** * Returns event information as json element based on the message protocol, - * taking message type and json body as input. - *

+ * taking message type and json body of string type as input because just to parse + * the string in to JsonElement not using JsonElement directly here. + * *

* Parameters: msgProtocol - The message protocol, which tells us which * service to invoke. msgType - The type of message that needs to be - * generated. bodyJson - The content of the message which is used in + * generated. body - The content of the message which is used in * creating the event details. *

* Returns: The event information as a json element */ + @ApiOperation(value = "To generate eiffel event based on the message protocol", response = String.class) - @ApiResponses(value = { @ApiResponse(code = 200, message = "Event sent successfully"), + @ApiResponses(value = {@ApiResponse(code = 200, message = "Event sent successfully"), @ApiResponse(code = 400, message = "Malformed JSON"), @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Message protocol is invalid") }) + @ApiResponse(code = 503, message = "Message protocol is invalid")}) @RequestMapping(value = "/{mp" + REGEX + "}", method = RequestMethod.POST) - public ResponseEntity generate( - @ApiParam(value = "message protocol", required = true) @PathVariable("mp") final String msgProtocol, - @ApiParam(value = "message type", required = true) @RequestParam("msgType") final String msgType, - @ApiParam(value = "ER lookup result multiple found, Generate will fail") @RequestParam(value = "failIfMultipleFound", required = false, defaultValue = "false") final Boolean failIfMultipleFound, - @ApiParam(value = "ER lookup result none found, Generate will fail") @RequestParam(value = "failIfNoneFound", required = false, defaultValue = "false") final Boolean failIfNoneFound, - @ApiParam(value = RemremGenerateServiceConstants.LOOKUP_IN_EXTERNAL_ERS) @RequestParam(value = "lookupInExternalERs", required = false, defaultValue = "false") final Boolean lookupInExternalERs, - @ApiParam(value = RemremGenerateServiceConstants.LOOKUP_LIMIT) @RequestParam(value = "lookupLimit", required = false, defaultValue = "1") final int lookupLimit, - @ApiParam(value = RemremGenerateServiceConstants.LenientValidation) @RequestParam(value = "okToLeaveOutInvalidOptionalFields", required = false, defaultValue = "false") final Boolean okToLeaveOutInvalidOptionalFields, - @ApiParam(value = "JSON message", required = true) @RequestBody JsonObject bodyJson) { + public ResponseEntity generate(@ApiParam(value = "message protocol", required = true) @PathVariable("mp") final String msgProtocol, + @ApiParam(value = "message type", required = true) @RequestParam("msgType") final String msgType, + @ApiParam(value = "ER lookup result multiple found, Generate will fail") @RequestParam(value = "failIfMultipleFound", required = false, defaultValue = "false") final Boolean failIfMultipleFound, + @ApiParam(value = "ER lookup result none found, Generate will fail") @RequestParam(value = "failIfNoneFound", required = false, defaultValue = "false") final Boolean failIfNoneFound, + @ApiParam(value = RemremGenerateServiceConstants.LOOKUP_IN_EXTERNAL_ERS) @RequestParam(value = "lookupInExternalERs", required = false, defaultValue = "false") final Boolean lookupInExternalERs, + @ApiParam(value = RemremGenerateServiceConstants.LOOKUP_LIMIT) @RequestParam(value = "lookupLimit", required = false, defaultValue = "1") final int lookupLimit, + @ApiParam(value = RemremGenerateServiceConstants.LenientValidation) @RequestParam(value = "okToLeaveOutInvalidOptionalFields", required = false, defaultValue = "false") final Boolean okToLeaveOutInvalidOptionalFields, + @ApiParam(value = "JSON message", required = true) @RequestBody String body) { + try { + JsonFactory jsonFactory = JsonFactory.builder().build().enable(com.fasterxml.jackson.core.JsonParser + .Feature.STRICT_DUPLICATE_DETECTION); + ObjectMapper mapper = new ObjectMapper(jsonFactory); + JsonNode node = mapper.readTree(body); + Gson gson = new Gson(); + JsonElement inputJson = gson.fromJson(node.toString(), JsonElement.class); + return generate(msgProtocol, msgType, failIfMultipleFound, failIfNoneFound, lookupInExternalERs, + lookupLimit, okToLeaveOutInvalidOptionalFields, inputJson); + } catch (JsonSyntaxException | JsonProcessingException e) { + String exceptionMessage = e.getMessage(); + log.error("Invalid JSON parse data format due to", exceptionMessage); + return createResponseEntity(HttpStatus.BAD_REQUEST, "Invalid JSON parse data format due to: " + + exceptionMessage, JSON_FATAL_STATUS); + } + } + /** + * Returns event information as json element based on the message protocol, + * taking message type and json body as input + * Here we basically add this to handle if inputData is of jsonArray type as well + *

+ * Parameters: msgProtocol - The message protocol, which tells us which + * service to invoke. msgType - The type of message that needs to be + * generated. inputData - The content of the message which is used in + * creating the event details. + *

+ * Returns: The event information as a json element + */ + public ResponseEntity generate(final String msgProtocol, final String msgType, final Boolean failIfMultipleFound, + final Boolean failIfNoneFound, final Boolean lookupInExternalERs, final int lookupLimit, + final Boolean okToLeaveOutInvalidOptionalFields, JsonElement inputData) { + + JsonArray generatedEventResults = new JsonArray(); try { - bodyJson = erLookup(bodyJson, failIfMultipleFound, failIfNoneFound, lookupInExternalERs, lookupLimit); - MsgService msgService = getMessageService(msgProtocol); - String response; - if (msgService != null) { - response = msgService.generateMsg(msgType, bodyJson, isLenientEnabled(okToLeaveOutInvalidOptionalFields)); - JsonElement parsedResponse = parser.parse(response); - if(lookupLimit <= 0) { - return new ResponseEntity<>("LookupLimit must be greater than or equals to 1", HttpStatus.BAD_REQUEST); + if (lookupLimit <= 0) { + return new ResponseEntity<>("Parameter 'lookupLimit' must be > 0", HttpStatus.BAD_REQUEST); + } + if (inputData == null) { + return createResponseEntity(HttpStatus.BAD_REQUEST, "Parameter 'inputData' must not be null", + JSON_ERROR_STATUS); + } + + if (inputData.isJsonArray()) { + JsonArray inputEventJsonArray = inputData.getAsJsonArray(); + for (JsonElement element : inputEventJsonArray) { + JsonObject generatedEvent = (processEvent(msgProtocol, msgType, + failIfMultipleFound, failIfNoneFound, lookupInExternalERs, lookupLimit, + okToLeaveOutInvalidOptionalFields, element.getAsJsonObject())); + generatedEventResults.add(generatedEvent); + } + boolean allSuccess = true; + boolean partialSuccess = false; + for (JsonElement result : generatedEventResults) { + JsonObject jsonObject = result.getAsJsonObject(); + allSuccess &= jsonObject.has(META); + partialSuccess |= jsonObject.has(META); } - if (!parsedResponse.getAsJsonObject().has(RemremGenerateServiceConstants.JSON_ERROR_MESSAGE_FIELD)) { - return new ResponseEntity<>(parsedResponse, HttpStatus.OK); + HttpStatus eventStatus = HttpStatus.BAD_REQUEST; + if (allSuccess){ + eventStatus = HttpStatus.OK; + } + else if (partialSuccess){ + eventStatus = HttpStatus.MULTI_STATUS; + } + return new ResponseEntity<>(generatedEventResults, eventStatus); + + } else if (inputData.isJsonObject()) { + JsonObject inputJsonObject = inputData.getAsJsonObject(); + JsonObject processedJson = processEvent(msgProtocol, msgType, failIfMultipleFound, failIfNoneFound, + lookupInExternalERs, lookupLimit, okToLeaveOutInvalidOptionalFields, inputJsonObject); + HttpStatus status; + if (processedJson.has(META)) { + status = HttpStatus.OK; + return new ResponseEntity<>(processedJson, status); + } else if (processedJson.has(JSON_STATUS_CODE)) { + String statusValue = processedJson.get(JSON_STATUS_CODE).toString(); + try { + status = HttpStatus.resolve(Integer.parseInt(statusValue)); + return new ResponseEntity<>(processedJson, status); + } catch (NumberFormatException e) { + String errorMessage = "Invalid status value: '" + statusValue + "' of response " + processedJson; + log.error(errorMessage); + return createResponseEntity(HttpStatus.BAD_REQUEST, errorMessage, JSON_ERROR_STATUS); + } } else { - return new ResponseEntity<>(parsedResponse, HttpStatus.BAD_REQUEST); + String errorMessage = "There is no status value in the response " + processedJson; + log.error(errorMessage); + return createResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR, errorMessage, JSON_ERROR_STATUS); } } else { - return new ResponseEntity<>(parser.parse(RemremGenerateServiceConstants.NO_SERVICE_ERROR), - HttpStatus.SERVICE_UNAVAILABLE); - } - } catch (REMGenerateException e1) { - if (e1.getMessage().contains(Integer.toString(HttpStatus.NOT_ACCEPTABLE.value()))) { - return new ResponseEntity<>(parser.parse(e1.getMessage()), HttpStatus.NOT_ACCEPTABLE); + return createResponseEntity(HttpStatus.BAD_REQUEST, + "Invalid JSON format,expected either single template or array of templates", + JSON_ERROR_STATUS); } - else if (e1.getMessage().contains(Integer.toString(HttpStatus.EXPECTATION_FAILED.value()))) { - return new ResponseEntity<>(parser.parse(e1.getMessage()), HttpStatus.EXPECTATION_FAILED); - } - else if (e1.getMessage().contains(Integer.toString(HttpStatus.EXPECTATION_FAILED.value()))) { - return new ResponseEntity<>(parser.parse(e1.getMessage()), HttpStatus.EXPECTATION_FAILED); - } - else if (e1.getMessage() - .contains(Integer.toString(HttpStatus.SERVICE_UNAVAILABLE.value()))) { - return new ResponseEntity<>(parser.parse(RemremGenerateServiceConstants.NO_ER), - HttpStatus.SERVICE_UNAVAILABLE); - } - else { - return new ResponseEntity<>(parser.parse(e1.getMessage()), HttpStatus.UNPROCESSABLE_ENTITY); + } catch (REMGenerateException | JsonSyntaxException e) { + return handleException(e); + } + } + + /** + * To display response in browser or application + * @param status response code for the HTTP request + * @param responseMessage the message according to response + * @param resultMessage whatever the result this message gives you idea about that + * @param errorResponse is to collect all the responses here. + * @return ResponseEntity + */ + public ResponseEntity createResponseEntity(HttpStatus status, String responseMessage, String resultMessage, + JsonObject errorResponse) { + initializeResponse(status, resultMessage, responseMessage, errorResponse); + return new ResponseEntity<>(errorResponse, status); + } + + /** + * To display response in browser or application + * @param status response code for the HTTP request + * @param responseMessage the message according to response + * @param resultMessage whatever the result this message gives you idea about that + * @return ResponseEntity + */ + public ResponseEntity createResponseEntity(HttpStatus status, String resultMessage, String responseMessage) { + return createResponseEntity(status, responseMessage, resultMessage, new JsonObject()); + } + + /** + * To initialize in the @{createResponseEntity} method + * @param status response code for the HTTP request + * @param resultMessage whatever the result this message gives you idea about that + * @param errorResponse is to collect all the responses here. + */ + public void initializeResponse(HttpStatus status, String resultMessage, String errorMessage, JsonObject errorResponse) { + errorResponse.addProperty(JSON_STATUS_CODE, status.value()); + errorResponse.addProperty(JSON_STATUS_RESULT, resultMessage); + errorResponse.addProperty(JSON_ERROR_MESSAGE_FIELD, errorMessage); + } + + /** + * To handle the exception in one method + * @param e taken general exception here + * @return ResponseEntity + */ + private ResponseEntity handleException(Exception e) { + String exceptionMessage = e.getMessage(); + if (e instanceof REMGenerateException) { + List statusList = List.of( + HttpStatus.NOT_ACCEPTABLE, HttpStatus.EXPECTATION_FAILED, HttpStatus.SERVICE_UNAVAILABLE, + HttpStatus.UNPROCESSABLE_ENTITY + ); + for (HttpStatus status : statusList) { + if (exceptionMessage.contains(Integer.toString(status.value()))) { + return createResponseEntity(status, exceptionMessage, JSON_ERROR_STATUS); + } } - } catch (Exception e) { - log.error("Unexpected exception caught", e); - return new ResponseEntity<>(parser.parse(RemremGenerateServiceConstants.INTERNAL_SERVER_ERROR), - HttpStatus.INTERNAL_SERVER_ERROR); + return createResponseEntity(HttpStatus.BAD_REQUEST, exceptionMessage, JSON_ERROR_STATUS); + } else if (e instanceof JsonSyntaxException) { + log.error("Failed to parse JSON", exceptionMessage); + return createResponseEntity(HttpStatus.BAD_REQUEST, exceptionMessage, JSON_ERROR_STATUS); + } else { + log.error("Unexpected exception caught", exceptionMessage); + return createResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR, exceptionMessage, JSON_ERROR_STATUS); + } + } + + /** + * This helper method basically generate or process single event + * @param msgProtocol The message protocol, which tells us which service to invoke + * @param msgType The type of message that needs to be generated. inputData + * @param failIfMultipleFound + * @param failIfNoneFound + * @param lookupInExternalERs + * @param lookupLimit + * @param okToLeaveOutInvalidOptionalFields + * @param jsonObject The content of the message which is used in creating the event details. + * @return JsonObject generated event + */ + public JsonObject processEvent(String msgProtocol, String msgType, Boolean failIfMultipleFound, + Boolean failIfNoneFound, Boolean lookupInExternalERs, int lookupLimit, + Boolean okToLeaveOutInvalidOptionalFields, JsonObject jsonObject) throws REMGenerateException, JsonSyntaxException { + JsonElement parsedResponse; + + JsonObject event = erLookup(jsonObject, failIfMultipleFound, failIfNoneFound, lookupInExternalERs, lookupLimit); + MsgService msgService = getMessageService(msgProtocol); + + if (msgService == null) { + return createResponseEntity(HttpStatus.SERVICE_UNAVAILABLE, + "No protocol service has been found registered", JSON_ERROR_STATUS).getBody(); + } + String response = msgService.generateMsg(msgType, event, isLenientEnabled(okToLeaveOutInvalidOptionalFields)); + parsedResponse = JsonParser.parseString(response); + JsonObject parsedJson = parsedResponse.getAsJsonObject(); + + if (parsedJson.has(JSON_ERROR_MESSAGE_FIELD)) { + JsonObject eventResponse = new JsonObject(); + createResponseEntity(HttpStatus.BAD_REQUEST, parsedJson.toString(), JSON_ERROR_STATUS, eventResponse); + return eventResponse; + } else { + return parsedJson; } } diff --git a/service/src/test/java/com/ericsson/eiffel/remrem/generate/service/EiffelRemremControllerUnitTest.java b/service/src/test/java/com/ericsson/eiffel/remrem/generate/service/EiffelRemremControllerUnitTest.java index a2c1dea..ddc1142 100644 --- a/service/src/test/java/com/ericsson/eiffel/remrem/generate/service/EiffelRemremControllerUnitTest.java +++ b/service/src/test/java/com/ericsson/eiffel/remrem/generate/service/EiffelRemremControllerUnitTest.java @@ -25,6 +25,9 @@ import java.util.ArrayList; import java.util.List; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,6 +36,7 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.Spy; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringRunner; @@ -53,11 +57,9 @@ public class EiffelRemremControllerUnitTest { @Mock MsgService service2; - @Spy private List msgServices = new ArrayList(); - @Mock JsonElement body; @@ -111,41 +113,104 @@ public void setUp() throws Exception { @Test public void testSemanticsSuccessEvent() throws Exception { - ResponseEntity elem = unit.generate("eiffelsemantics", "eiffelactivityfinished", false, false, true, 1, false, body.getAsJsonObject()); + File file = new File("src/test/resources/ErlookupConfidenceLevelOutput.json"); + JsonParser parser = new JsonParser(); + JsonObject json = parser.parse(new FileReader(file)).getAsJsonObject(); + ResponseEntity elem = unit.generate("eiffelsemantics", "eiffelactivityfinished", false, false, true, 1, false, json); assertEquals(elem.getStatusCode(), HttpStatus.OK); } + @Test + public void testSemanticsSuccessArrayEvent() throws Exception { + File file = new File("src/test/resources/ErlookupConfidenceLevelArrayOutput.json"); + JsonParser parser = new JsonParser(); + JsonArray json = parser.parse(new FileReader(file)).getAsJsonArray(); + ResponseEntity elem = unit.generate("eiffelsemantics", "eiffelactivityfinished", false, false, true, 1, false, json); + assertEquals(elem.getStatusCode(), HttpStatus.OK); + } + + @Test public void testSemanticsFailureEvent() throws Exception { - ResponseEntity elem = unit.generate("eiffelsemantics", "EiffelActivityFinished", false, false, true, 1, false, body.getAsJsonObject()); + File file = new File("src/test/resources/ErlookupConfidenceLevelOutput.json"); + JsonParser parser = new JsonParser(); + JsonObject json = parser.parse(new FileReader(file)).getAsJsonObject(); + ResponseEntity elem = unit.generate("eiffelsemantics", "EiffelActivityFinished", false, false, true, 1, false, json); + assertEquals(elem.getStatusCode(), HttpStatus.BAD_REQUEST); + } + + @Test + public void testSemanticsFailureEventArray() throws Exception { + File file = new File("src/test/resources/ErlookupConfidenceLevelArrayOutput.json"); + JsonParser parser = new JsonParser(); + JsonArray json = parser.parse(new FileReader(file)).getAsJsonArray(); + ResponseEntity elem = unit.generate("eiffelsemantics", "EiffelActivityFinished", false, false, true, 1, false, json); assertEquals(elem.getStatusCode(), HttpStatus.BAD_REQUEST); } @Test public void testEiffel3SuccessEvent() throws Exception { - ResponseEntity elem = unit.generate("eiffel3", "eiffelartifactnew", false, false, true, 1, false, body.getAsJsonObject()); + File file = new File("src/test/resources/ErlookupConfidenceLevelOutput.json"); + JsonParser parser = new JsonParser(); + JsonObject json = parser.parse(new FileReader(file)).getAsJsonObject(); + ResponseEntity elem = unit.generate("eiffel3", "eiffelartifactnew", false, false, true, 1, false, json); + assertEquals(elem.getStatusCode(), HttpStatus.OK); + } + + @Test + public void testEiffel3SuccessEventArray() throws Exception { + File file = new File("src/test/resources/ErlookupConfidenceLevelArrayOutput.json"); + JsonParser parser = new JsonParser(); + JsonArray json = parser.parse(new FileReader(file)).getAsJsonArray(); + ResponseEntity elem = unit.generate("eiffel3", "eiffelartifactnew", false, false, true, 1, false, json); assertEquals(elem.getStatusCode(), HttpStatus.OK); } @Test public void testEiffel3FailureEvent() throws Exception { - ResponseEntity elem = unit.generate("eiffel3", "eiffelartifactnewevent", false, false, true, 1, false, body.getAsJsonObject()); + File file = new File("src/test/resources/ErlookupConfidenceLevelOutput.json"); + JsonParser parser = new JsonParser(); + JsonObject json = parser.parse(new FileReader(file)).getAsJsonObject(); + ResponseEntity elem = unit.generate("eiffel3", "eiffelartifactnewevent", false, false, true, 1, false, json); assertEquals(elem.getStatusCode(), HttpStatus.BAD_REQUEST); } + @Test + public void testEiffel3FailureEventArray() throws Exception { + File file = new File("src/test/resources/ErlookupConfidenceLevelArrayOutput.json"); + JsonParser parser = new JsonParser(); + JsonArray json = parser.parse(new FileReader(file)).getAsJsonArray(); + ResponseEntity elem = unit.generate("eiffel3", "eiffelartifactnewevent", false, false, true, 1, false, json); + assertEquals(elem.getStatusCode(), HttpStatus.BAD_REQUEST); + } @Test public void testMessageServiceUnavailableEvent() throws Exception { - ResponseEntity elem = unit.generate("other", "EiffelActivityFinishedEvent", false, false, true, 1, false, body.getAsJsonObject()); + File file = new File("src/test/resources/ArtifactCreated.json"); + JsonParser parser = new JsonParser(); + JsonObject json = parser.parse(new FileReader(file)).getAsJsonObject(); + ResponseEntity elem = unit.generate("other", "EiffelActivityFinishedEvent", false, false, true, 1, false, json); assertEquals(elem.getStatusCode(), HttpStatus.SERVICE_UNAVAILABLE); } @Test public void testlenientValidation() throws Exception { + File file = new File("src/test/resources/ArtifactCreated.json"); + JsonParser parser = new JsonParser(); + JsonObject json = parser.parse(new FileReader(file)).getAsJsonObject(); unit.setLenientValidationEnabledToUsers(true); - ResponseEntity elem = unit.generate("eiffelsemantics", "EiffelArtifactCreatedEvent", false, false, true, 1, true, body.getAsJsonObject()); + ResponseEntity elem = unit.generate("eiffelsemantics", "EiffelArtifactCreatedEvent", false, false, true, 1, true, json); assertEquals(elem.getStatusCode(), HttpStatus.OK); } + @Test + public void testlenientValidationEventArray() throws Exception { + File file = new File("src/test/resources/ArtifactCreatedEventArray.json"); + JsonParser parser = new JsonParser(); + JsonArray json = parser.parse(new FileReader(file)).getAsJsonArray(); + unit.setLenientValidationEnabledToUsers(true); + ResponseEntity elem = unit.generate("eiffelsemantics", "EiffelArtifactCreatedEvent", false, false, true, 1, true, json); + assertEquals(elem.getStatusCode(), HttpStatus.OK); + } @Test public void testJasyptFileSuccess() throws IOException { String jasyptPath = "src/test/resources/jasypt.key"; diff --git a/service/src/test/resources/ArtifactCreatedEventArray.json b/service/src/test/resources/ArtifactCreatedEventArray.json new file mode 100644 index 0000000..6561ea6 --- /dev/null +++ b/service/src/test/resources/ArtifactCreatedEventArray.json @@ -0,0 +1,138 @@ +[ + { + "msgParams": { + "meta": { + "type": "EiffelArtifactCreatedEvent", + "version": "3.0.0", + "tags": [ + "tag1", + "tag2" + ], + "source": { + "domainId": "domainID", + "host": "host", + "name": "name", + "uri": "http:\/\/java.sun.com\/j2se\/1.3\/", + "serializer":"pkg:maven" + }, + "security": { + "authorIdentity": "test", + "encryptedDigest": "sample" + } + } + }, + "eventParams": { + "data": { + "gav": { + "groupId": "G", + "artifactId": "A", + "version": "V" + }, + "fileInformation": [{ + "name":"name" + }], + "buildCommand": "trigger", + "requiresImplementation": "NONE", + "name": "event", + "dependsOn": [ + ], + "implement": [ + ], + "identity":"pkg:abc", + "customData": [{ + "key": "firstLog", + "value": "http:\/\/myHost.com\/firstLog" + }, + { + "key": "otherLog", + "value": "http:\/\/myHost.com\/firstLog33" + } + ] + }, + "links": [{ + "type": "CAUSE", + "target": "aaaaaaaa-bbbb-5ccc-8ddd-eeeeeeeeeee1" + }, + { + "type": "PREVIOUS_VERSION", + "target": "aaaaaaaa-bbbb-5ccc-8ddd-eeeeeeeeeee2" + }, + { + "type": "COMPOSITION", + "target": "aaaaaaaa-bbbb-5ccc-8ddd-eeeeeeeeeee1" + }, + { + "type": "ENVIRONMENT", + "target": "aaaaaaaa-bbbb-5ccc-8ddd-eeeeeeeeeee3" + }] + } + }, + { + "msgParams": { + "meta": { + "type": "EiffelArtifactCreatedEvent", + "version": "3.0.0", + "tags": [ + "tag1", + "tag2" + ], + "source": { + "domainId": "domainID", + "host": "host", + "name": "name", + "uri": "http:\/\/java.sun.com\/j2se\/1.3\/", + "serializer":"pkg:maven" + }, + "security": { + "authorIdentity": "test", + "encryptedDigest": "sample" + } + } + }, + "eventParams": { + "data": { + "gav": { + "groupId": "G", + "artifactId": "A", + "version": "V" + }, + "fileInformation": [{ + "name":"name" + }], + "buildCommand": "trigger", + "requiresImplementation": "NONE", + "name": "event", + "dependsOn": [ + ], + "implement": [ + ], + "identity":"pkg:abc", + "customData": [{ + "key": "firstLog", + "value": "http:\/\/myHost.com\/firstLog" + }, + { + "key": "otherLog", + "value": "http:\/\/myHost.com\/firstLog33" + } + ] + }, + "links": [{ + "type": "CAUSE", + "target": "aaaaaaaa-bbbb-5ccc-8ddd-eeeeeeeeeee1" + }, + { + "type": "PREVIOUS_VERSION", + "target": "aaaaaaaa-bbbb-5ccc-8ddd-eeeeeeeeeee2" + }, + { + "type": "COMPOSITION", + "target": "aaaaaaaa-bbbb-5ccc-8ddd-eeeeeeeeeee1" + }, + { + "type": "ENVIRONMENT", + "target": "aaaaaaaa-bbbb-5ccc-8ddd-eeeeeeeeeee3" + }] + } + } +] \ No newline at end of file diff --git a/service/src/test/resources/ErlookupConfidenceLevelArrayOutput.json b/service/src/test/resources/ErlookupConfidenceLevelArrayOutput.json new file mode 100644 index 0000000..f004f9f --- /dev/null +++ b/service/src/test/resources/ErlookupConfidenceLevelArrayOutput.json @@ -0,0 +1,78 @@ +[ + { + "meta": { + "id": "dd595536-e8e4-4526-b959-8bb7e105d40d", + "type": "EiffelActivityFinishedEvent", + "version": "1.0.0", + "time": 1481281099889, + "tags": ["tag1", "tag2"], + "source": { + "domainId": "domainID", + "host": "host", + "name": "name", + "serializer": { + "groupId": "G", + "artifactId": "A", + "version": "V" + }, + "uri": "http://java.sun.com/j2se/1.3/" + } + }, + "data": { + "outcome": { + "conclusion": "TIMED_OUT", + "description": "Compilation timed out." + }, + "persistentLogs": [{ + "name": "firstLog", + "uri": "http://myHost.com/firstLog" + }, { + "name": "otherLog", + "uri": "http://myHost.com/firstLog33" + }], + "customData": [] + }, + "links": [{ + "type": "LinkTargetType", + "target": "LinkTarget" + }] + }, + { + "meta": { + "id": "dd595536-e8e4-4526-b959-8bb7e105d40d", + "type": "EiffelActivityFinishedEvent", + "version": "1.0.0", + "time": 1481281099889, + "tags": ["tag1", "tag2"], + "source": { + "domainId": "domainID", + "host": "host", + "name": "name", + "serializer": { + "groupId": "G", + "artifactId": "A", + "version": "V" + }, + "uri": "http://java.sun.com/j2se/1.3/" + } + }, + "data": { + "outcome": { + "conclusion": "TIMED_OUT", + "description": "Compilation timed out." + }, + "persistentLogs": [{ + "name": "firstLog", + "uri": "http://myHost.com/firstLog" + }, { + "name": "otherLog", + "uri": "http://myHost.com/firstLog33" + }], + "customData": [] + }, + "links": [{ + "type": "LinkTargetType", + "target": "LinkTarget" + }] + } +] \ No newline at end of file diff --git a/wiki/markdown/usage/service.md b/wiki/markdown/usage/service.md index 81cb92a..436b752 100644 --- a/wiki/markdown/usage/service.md +++ b/wiki/markdown/usage/service.md @@ -127,16 +127,259 @@ The response generated will have internal status codes for each and every event Status codes are generated according to the below table. -| Status code | Result | Message | Comment | -|-------------|-----------------------|---------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------| -| 200 | OK | | Event generated successfully | -| 400 | Bad Request | Could not read document: Unrecognized token | Malformed JSON (missing braces or wrong event type, etc..), client need to fix problem in event before submitting again | -| 404 | Not Found | Requested template is not available | The endpoint is not found, or template for specified event type is not found | -| 406 | Not Acceptable | No event id found with ERLookup properties, Lenient Validation disabled in configuration and user requested through REST call | Is returned if no event id fetched from configured event repository in REMReM generate, Lenient validation is not enabled in configuration, your not alloed to use this option. | -| 417 | Expectation Failed | Multiple event ids found with ERLookup properties | Is returned if multiple event ids fetched from configured event repository in REMReM generate. | -| 422 | Unprocessable Entity | Link specific lookup options could not be fulfilled | Is returned if Link specific lookup options could not be matched with failIfMultipleFound and failIfNoneFound. | -| 500 | Internal Server Error | Internal server error | When REMReM Generate is down, possible to try again later when server is up | -| 503 | Service Unavailable | "No protocol service has been found registered" | When specified message protocol is not loaded | +| Status code | Result | Message | Comment | +|-------------|-----------------------|-------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 200 | OK | | Event generated successfully | +| 207 | Multi Status | Multi-Status | Is returned when there's a partial success, i.e. some events failed, some successfully generated, return status should be 207. | +| 400 | Bad Request | Could not read document: Unrecognized token | Malformed JSON (missing braces or wrong event type, etc..), client need to fix problem in event before submitting again | +| 404 | Not Found | Requested template is not available | The endpoint is not found, or template for specified event type is not found | +| 406 | Not Acceptable | No event id found with ERLookup properties, Lenient Validation disabled in configuration and user requested through REST call | Is returned if no event id fetched from configured event repository in REMReM generate, Lenient validation is not enabled in configuration, your not alloed to use this option. | +| 417 | Expectation Failed | Multiple event ids found with ERLookup properties | Is returned if multiple event ids fetched from configured event repository in REMReM generate. | +| 422 | Unprocessable Entity | Link specific lookup options could not be fulfilled | Is returned if Link specific lookup options could not be matched with failIfMultipleFound and failIfNoneFound. | +| 500 | Internal Server Error | Internal server error | When REMReM Generate is down, possible to try again later when server is up | +| 503 | Service Unavailable | "No protocol service has been found registered" | When specified message protocol is not loaded | + + +NOTE: In the array of event if any of the event have not valid JSON format, +then in response body we have only one response for that invalid JSON event, it is because the parser can't parse the invalid JSON format here. + +### Examples: + +There is some examples of passing an array of events and what their responses can be + +#### Templates for successful array of events : + +``` +[{ + "msgParams": { + "meta": {........ + "source": {......} + } + }, + "eventParams": { + "data": {......}, + "links": [ + { + "type": "ACTIVITY_EXECUTION", + "target": "2d4849ec-53b9-4c3f-8b15-390d0ff33cfc" + } + ]}}, +{ + "msgParams": { + "meta": {........ + "source": {......} + } + }, + "eventParams": { + "data": {......}, + "links": [ + { + "type": "ACTIVITY_EXECUTION", + "target": "2d4849ec-53b9-4c3f-8b15-390d0ff33cfc" + } + ] + }}] + +``` + +#### Response body: + +``` +[ + { + "meta": { + "id": "e878b4dc-7f4e-4bb3-9568-60fa23f014e2", + "type": "EiffelActivityFinishedEvent", + "version": "3.0.0", + "time": 1723455277403, + "tags": [""], + "source": { + "domainId": "", + "host": "", + "name": "", + "serializer": "pkg:maven/com.github.eiffel-community/eiffel-remrem-semantics@2.2.7", + "uri": "" + }}, + "data": { + "outcome": { + "conclusion": "SUCCESSFUL", + "description": ""}, + "persistentLogs": [], + "customData": [] + }, + "links": [ + { + "type": "ACTIVITY_EXECUTION", + "target": "2d4849ec-53b9-4c3f-8b15-390d0ff33cfc" + } + ]}, + { + "meta": { + "id": "a0729ad7-d067-4227-b570-6c0fa6d58ace", + "type": "EiffelActivityFinishedEvent", + "version": "3.0.0", + "time": 1723455277406, + "tags": [""], + "source": { + "domainId": "", + "host": "", + "name": "", + "serializer": "pkg:maven/com.github.eiffel-community/eiffel-remrem-semantics@2.2.7", + "uri": "" + }}, + "data": { + "outcome": { + "conclusion": "SUCCESSFUL", + "description": ""}, + "persistentLogs": [], + "customData": [] + }, + "links": [ + { + "type": "ACTIVITY_EXECUTION", + "target": "2d4849ec-53b9-4c3f-8b15-390d0ff33cfc" + } + ]}] + +``` + +#### Response: + +200 + +In the above array of event both the event template is correct, so that's why response code is appeared as 200 + +#### Template for partial successful or unsuccessful array of events : + +``` +[{ + "msgParams": { + "meta": {........ + "source": {......} + } + }, + "eventParams": { + "data": {......}, + "links": [ + { + "type": "ACTIVITY_EXECUTION", + "target": "2d4849ec-53b9-4c3f-8b15-390d0ff33cfc" + } + ]}}, +{ + "msgParams": { + "meta": {........ + "source": {......} + }}, + "eventParams": { + "data": {......}, + "links": [ + { + "type": "INCORRECT_TYPE", //Mandatory link type ACTIVITY_EXECUTION is missing + "target": "2d4849ec-53b9-4c3f-8b15-390d0ff33cfc" + } + ] + }}] + +``` + +#### Response body: + +``` +[ + { + "meta": { + "id": "feba19dc-c095-437e-98f1-a8a5ada7fa25", + "type": "EiffelActivityFinishedEvent", + "version": "3.0.0", + "time": 1723452800241, + "tags": [""], + "source": {...} + }, + "data": { + "outcome": {....}, + "persistentLogs": [], + "customData": []}, + "links": [ + { + "type": "ACTIVITY_EXECUTION", + "target": "2d4849ec-53b9-4c3f-8b15-390d0ff33cfc" + } + ] + }, + { + "status code": 400, + "result": "FAIL", + "message": "{\"message\":\"Cannot validate given JSON string\",\"cause\":\"com.ericsson.eiffel.remrem.semantics.validator.EiffelValidationException: Mandatory link type ACTIVITY_EXECUTION is missing\"}" + } +] + +``` + +#### Response: + +207 + +In the above array of event, in the first template links type is missing and for second one links type is there, so first one is correct and second one is incorrect. +So that's why in response we have multi status and it appeared as 207. + + +#### Template for all unsuccessful array of events : + +``` +[{ + "msgParams": { + "meta": {........ + "source": {......} + } + }, + "eventParams": { + "data": {......}, + "links": [ + { + "type": "INCORRECT_TYPE", //Mandatory link type ACTIVITY_EXECUTION is missing + "target": "2d4849ec-53b9-4c3f-8b15-390d0ff33cfc" + } + ]}}, + { + "msgParams": { + "meta": {........ + "source": {......} + }}, + "eventParams": { + "data": {......}, + "links": [ + { + "type": "INCORRECT_TYPE", //Mandatory link type ACTIVITY_EXECUTION is missing + "target": "2d4849ec-53b9-4c3f-8b15-390d0ff33cfc" + } + ] + }}] + +``` + +#### Response body: + +``` +[ + { + "status code": 400, + "result": "FAIL", + "message": "{\"message\":\"Cannot validate given JSON string\",\"cause\":\"com.ericsson.eiffel.remrem.semantics.validator.EiffelValidationException: Mandatory link type ACTIVITY_EXECUTION is missing\"}" + }, + { + "status code": 400, + "result": "FAIL", + "message": "{\"message\":\"Cannot validate given JSON string\",\"cause\":\"com.ericsson.eiffel.remrem.semantics.validator.EiffelValidationException: Mandatory link type ACTIVITY_EXECUTION is missing\"}" + } +] + +``` +#### Response: + +400 + +In the above array of event both the event template have not links type that's make him an incorrect event, So that's why the response is appeared as 400. ## Lookups