Permalink
Browse files

wrapped responses

  • Loading branch information...
arcuri82 committed Nov 5, 2018
1 parent 36853fe commit 8ea5093433a1ace6ab146e3f8e079b7adf78e76d
@@ -0,0 +1,47 @@
package org.evomaster.clientJava.controllerApi.dto;
import java.util.Objects;
/**
* In REST, when we have an error, at most we would see a HTTP
* status code.
* But it can be very useful to get an actual description of the error.
* So, it is a common practice to have "Wrapped Responses", which can
* contain the error message (if any)
*
* Created by arcuri82 on 05-Nov-18.
*/
public class WrappedResponseDto<T> {
/**
* The actual payload we are sending and are "wrapping" here
*/
public T data;
/**
* A message describing the error, if any.
* If this is not null, then "data" must be null.
*/
public String error;
public static <K> WrappedResponseDto<K> withData(K data){
WrappedResponseDto<K> dto = new WrappedResponseDto<>();
dto.data = data;
return dto;
}
public static WrappedResponseDto<?> withNoData(){
return new WrappedResponseDto<>();
}
public static WrappedResponseDto<?> withError(String error){
Objects.requireNonNull(error);
if(error.isEmpty()){
throw new IllegalArgumentException("Empty error message");
}
WrappedResponseDto<?> dto = new WrappedResponseDto<>();
dto.error = error;
return dto;
}
}
@@ -13,6 +13,7 @@
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.sql.Connection;
import java.util.Arrays;
import java.util.List;
@@ -28,6 +29,7 @@
* as we might need to re-implement it in different languages.
*/
@Path("")
@Produces(Formats.JSON_V1)
public class EMController {
private final SutController sutController;
@@ -40,8 +42,7 @@ public EMController(SutController sutController) {
@Path(ControllerConstants.INFO_SUT_PATH)
@GET
@Produces(Formats.JSON_V1)
public SutInfoDto getSutInfo() {
public Response getSutInfo() {
SutInfoDto dto = new SutInfoDto();
dto.isSutRunning = sutController.isSutRunning();
@@ -52,48 +53,55 @@ public SutInfoDto getSutInfo() {
ProblemInfo info = sutController.getProblemInfo();
if(info == null){
SimpleLogger.error("ERROR -> undefined problem type");
String msg = "Undefined problem type in the EM Controller";
SimpleLogger.error(msg);
return Response.status(500).entity(WrappedResponseDto.withError(msg)).build();
} else if (info instanceof RestProblem){
RestProblem rp = (RestProblem) info;
dto.restProblem = new RestProblemDto();
dto.restProblem.swaggerJsonUrl = rp.getSwaggerJsonUrl();
dto.restProblem.endpointsToSkip = rp.getEndpointsToSkip();
} else {
SimpleLogger.error("ERROR -> unrecognized type " + info.getClass().getName());
String msg = "Unrecognized problem type: " + info.getClass().getName();
SimpleLogger.error(msg);
return Response.status(500).entity(WrappedResponseDto.withError(msg)).build();
}
return dto;
return Response.status(200).entity(WrappedResponseDto.withData(dto)).build();
}
@Path(ControllerConstants.CONTROLLER_INFO)
@GET
@Produces(Formats.JSON_V1)
public ControllerInfoDto getControllerInfoDto() {
public Response getControllerInfoDto() {
ControllerInfoDto dto = new ControllerInfoDto();
dto.fullName = sutController.getClass().getName();
dto.isInstrumentationOn = sutController.isInstrumentationActivated();
return dto;
return Response.status(200).entity(WrappedResponseDto.withData(dto)).build();
}
@Path(ControllerConstants.NEW_SEARCH)
@POST
public void newSearch() {
public Response newSearch() {
sutController.newSearch();
return Response.status(201).entity(WrappedResponseDto.withNoData()).build();
}
@Path(ControllerConstants.RUN_SUT_PATH)
@PUT
@Consumes(Formats.JSON_V1)
public void runSut(SutRunDto dto) {
public Response runSut(SutRunDto dto) {
try {
if (dto.run == null) {
String msg = "Invalid JSON: 'run' field is required";
SimpleLogger.warn(msg);
throw new WebApplicationException(msg, 400);
return Response.status(400).entity(WrappedResponseDto.withError(msg)).build();
}
boolean newlyStarted = false;
@@ -104,7 +112,9 @@ public void runSut(SutRunDto dto) {
baseUrlOfSUT = sutController.startSut();
if (baseUrlOfSUT == null) {
//there has been an internal failure in starting the SUT
throw new WebApplicationException("Internal failure: cannot start SUT based on given configuration", 500);
String msg = "Internal failure: cannot start SUT based on given configuration";
SimpleLogger.warn(msg);
return Response.status(500).entity(WrappedResponseDto.withError(msg)).build();
}
sutController.initSqlHandler();
sutController.newTest();
@@ -124,7 +134,7 @@ public void runSut(SutRunDto dto) {
if (!dto.run) {
String msg = "Invalid JSON: cannot reset state and stop service at same time";
SimpleLogger.warn(msg);
throw new WebApplicationException(msg, 400);
return Response.status(400).entity(WrappedResponseDto.withError(msg)).build();
}
if (!newlyStarted) { //no point resetting if fresh start
@@ -140,16 +150,18 @@ public void runSut(SutRunDto dto) {
But even after spending hours googling it, haven't managed to configure it
*/
SimpleLogger.error("ERROR -> " + e.getMessage());
throw e;
String msg = e.getMessage();
SimpleLogger.error(msg );
return Response.status(500).entity(WrappedResponseDto.withError(msg)).build();
}
return Response.status(204).entity(WrappedResponseDto.withNoData()).build();
}
@Path(ControllerConstants.TARGETS_PATH)
@GET
@Produces(Formats.JSON_V1)
public TargetsResponseDto getTargets(
public Response getTargets(
@QueryParam("ids")
@DefaultValue("")
String idList) {
@@ -166,14 +178,14 @@ public TargetsResponseDto getTargets(
} catch (NumberFormatException e) {
String msg = "Invalid parameter 'ids': " + e.getMessage();
SimpleLogger.warn(msg);
throw new WebApplicationException(msg, e);
return Response.status(400).entity(WrappedResponseDto.withError(msg)).build();
}
List<TargetInfo> list = sutController.getTargetInfos(ids);
if (list == null) {
String msg = "Failed to collect target information for " + ids.size() + " ids";
SimpleLogger.error(msg);
throw new WebApplicationException(msg, 500);
return Response.status(500).entity(WrappedResponseDto.withError(msg)).build();
}
list.forEach(t -> {
@@ -186,59 +198,62 @@ public TargetsResponseDto getTargets(
dto.targets.add(info);
});
return dto;
return Response.status(200).entity(WrappedResponseDto.withData(dto)).build();
}
@Path(ControllerConstants.EXTRA_HEURISTICS)
@GET
@Produces(Formats.JSON_V1)
public ExtraHeuristicDto getExtra() {
public Response getExtra() {
ExtraHeuristicDto dto = sutController.getExtraHeuristics();
return dto;
return Response.status(200).entity(WrappedResponseDto.withData(dto)).build();
}
@Path(ControllerConstants.EXTRA_HEURISTICS)
@DELETE
public void deleteExtra() {
public Response deleteExtra() {
sutController.resetExtraHeuristics();
return Response.status(204).entity(WrappedResponseDto.withNoData()).build();
}
@Path(ControllerConstants.NEW_ACTION)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Consumes(MediaType.APPLICATION_JSON)
@PUT
public void newAction(@FormParam("index") int index) {
public Response newAction(int index) {
sutController.newAction(index);
return Response.status(204).entity(WrappedResponseDto.withNoData()).build();
}
@Path(ControllerConstants.DATABASE_COMMAND)
@Consumes(Formats.JSON_V1)
@POST
public void executeDatabaseCommand(DatabaseCommandDto dto) {
public Response executeDatabaseCommand(DatabaseCommandDto dto) {
Connection connection = sutController.getConnection();
if (connection == null) {
String msg = "No active database connection";
SimpleLogger.warn(msg);
throw new WebApplicationException(msg, 400);
return Response.status(400).entity(WrappedResponseDto.withError(msg)).build();
}
if (dto.command == null && (dto.insertions == null || dto.insertions.isEmpty())) {
String msg = "No input command";
SimpleLogger.warn(msg);
throw new WebApplicationException(msg, 400);
return Response.status(400).entity(WrappedResponseDto.withError(msg)).build();
}
if (dto.command != null && dto.insertions != null && !dto.insertions.isEmpty()) {
String msg = "Only 1 command can be specified";
SimpleLogger.warn(msg);
throw new WebApplicationException(msg, 400);
return Response.status(400).entity(WrappedResponseDto.withError(msg)).build();
}
@@ -251,7 +266,9 @@ public void executeDatabaseCommand(DatabaseCommandDto dto) {
} catch (Exception e) {
String msg = "Failed to execute database command: " + e.getMessage();
SimpleLogger.warn(msg);
throw new WebApplicationException(msg, 400);
return Response.status(400).entity(WrappedResponseDto.withError(msg)).build();
}
return Response.status(204).entity(WrappedResponseDto.withNoData()).build();
}
}
@@ -111,7 +111,7 @@ public void testNotRunning(){
.get("/infoSUT")
.then()
.statusCode(200)
.body("isSutRunning", is(false));
.body("data.isSutRunning", is(false));
}
@Test
@@ -124,7 +124,7 @@ public void testStartDirect(){
.get("/infoSUT")
.then()
.statusCode(200)
.body("isSutRunning", is(true));
.body("data.isSutRunning", is(true));
}
@Test
@@ -138,7 +138,7 @@ public void testStartRest(){
.get("/infoSUT")
.then()
.statusCode(200)
.body("isSutRunning", is(true));
.body("data.isSutRunning", is(true));
}
@@ -149,6 +149,6 @@ public void testGetSwaggerUrl(){
.get("/infoSUT")
.then()
.statusCode(200)
.body("restProblem.swaggerJsonUrl", is(SWAGGER_URL));
.body("data.restProblem.swaggerJsonUrl", is(SWAGGER_URL));
}
}
@@ -160,7 +160,7 @@ public void testRetrieveSchema() throws Exception {
.get(url + BASE_PATH + INFO_SUT_PATH)
.then()
.statusCode(200)
.body("sqlSchemaDto.tables.size()", is(2));
.body("data.sqlSchemaDto.tables.size()", is(2));
}
@Test
@@ -95,26 +95,26 @@ public void testHeuristic() throws Exception {
.get(url)
.then()
.statusCode(200)
.body("toMinimize.size()", is(0));
.body("data.toMinimize.size()", is(0));
SqlScriptRunner.execCommand(getConnection(), "SELECT x FROM Foo WHERE x = 12");
given().accept(ContentType.JSON)
.get(url)
.then()
.statusCode(200)
.body("toMinimize.size()", is(1))
.body("toMinimize[0]", greaterThan(0f));
.body("data.toMinimize.size()", is(1))
.body("data.toMinimize[0]", greaterThan(0f));
SqlScriptRunner.execCommand(getConnection(), "SELECT x FROM Foo WHERE x = 10");
given().accept(ContentType.JSON)
.get(url)
.then()
.statusCode(200)
.body("toMinimize.size()", is(2))
.body("toMinimize[0]", greaterThan(0f))
.body("toMinimize[1]", is(0f));
.body("data.toMinimize.size()", is(2))
.body("data.toMinimize[0]", greaterThan(0f))
.body("data.toMinimize[1]", is(0f));
given().delete(url)
.then()
@@ -124,7 +124,7 @@ public void testHeuristic() throws Exception {
.get(url)
.then()
.statusCode(200)
.body("toMinimize.size()", is(0));
.body("data.toMinimize.size()", is(0));
} finally {
starter.stop();
@@ -225,7 +225,7 @@ private Double getFirstAndDelete(String url) {
.get(url)
.then()
.statusCode(200)
.extract().body().path("toMinimize[0]").toString());
.extract().body().path("data.toMinimize[0]").toString());
given().delete(url).then().statusCode(204);
return value;
Oops, something went wrong.

0 comments on commit 8ea5093

Please sign in to comment.