Reputation: 201
I have created this awesome controller point:
@Named
@Path("/awsome")
@Api(value = "An Awsome api")
public class AwsomeEndpoint extends BaseEndpoint {
@GET
@Path("{isThisAwsome}")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Get organisation by isthisAwsome",
notes = "Get AwsomeAnswer matching the given isThisAwsome.",
responseContainer = "single result",
response = JsonOrganisation.class)
@ApiResponses(value = {@ApiResponse(code = 200, message = "Awsome found"),
@ApiResponse(code = 404, message = "Awsome not found"),
@ApiResponse(code = 500, message = "Internal Error")})
public Response getAwsomeResponse(@PathParam("isThisAwsome") String isThisAwsome) {
Response response = handleErrors(() -> Response.ok(AwsomeResponseTransformer.transform(awsomeService.getAwsomeByisThisAwsome(isThisAwsome))).build());
return response;
}
}
This code uses a Lamda to handle the error flow:
public class BaseEndpoint {
protected Response handleErrors(Supplier<Response> responseSupplier) {
Response response;
try {
response = responseSupplier.get();
} catch (AwsomeRuntimeException e) {
response = createExceptionResponse(e);
}
return response;
}
private Response createExceptionResponse(AwsomeRuntimeException e) {
Response.ResponseBuilder response;
if (e.getExceptionStatus() == ExceptionStatus.NOT_FOUND) {
response = Response.status(Status.NOT_FOUND).entity(e.getMessage());
} else if (e.getExceptionStatus() == ExceptionStatus.ILLEGAL_ARGUMENT) {
response = Response.status(Status.BAD_REQUEST).entity(e.getMessage());
} else {
response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage());
}
return response.header("","").header("Pragma", "no-cache, no-store").header("Cache-Control", "no-cache, no-store").header("Expires", "0").build();
}}
For this I created some Pact test, all pacts work except when we i mock an error being thrown by the service we call.
An example of the pact test class:
RunWith(PactRunner.class)
@Provider("awsome")
@PactBroker(authentication=@PactBrokerAuth(username = "${pact.broker.username:x}", password = "${pact.broker.password:x}"),
protocol="${pact.broker.protocol:https}", host="${pact.broker.host:hosted.pact.dius.com.au}", port="${pact.broker.port:443}",
failIfNoPactsFound=false)
public class AccMgtPactIntegrationTest extends JerseyTest {
@TestTarget public final HttpTarget target = new HttpTarget(getPort());
private AwsomeService awsomeService;
private UserService userService;
@Override
protected ResourceConfig configure() {
awsomeService = mock(AwsomeService.class);
return new ResourceConfig().register(new OrganisationsEndpoint(awsomeService)).register(new AwsomeEndpoint())
// .property(ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, "true")
;
}
@State("Notn found")
public void whenOrganisationWithShortNameDoesNotExist() {
when(awsomeService.getOrganisationByShortName("WME")).thenThrow(new AwsomeRuntimeException(ExceptionStatus.NOT_FOUND));
} }
Now I get some weard errors from Pact, and I think its not pact thats the problem but how girlzy works in pact. Becoue I get the folowing error:
Verifying a pact between consumer and aswsome Given when
organisation with shortName does not exist Get awsome by isItAwsome
returns a response which
has status code 404 (OK)
includes headers
"Content-Type" with value "application/json" (FAILED)
has a matching body (FAILED)
Failures:
0) Get organisation by short name returns a response which includes headers "Content-Type" with value "application/json" Expected header 'Content-Type' to have value 'application/json' but was 'text/html;charset=ISO-8859-1'
1) Get organisation by short name returns a response which has a matching body comparison -> Expected a response type of 'application/json' but the actual type was 'text/html'
Now if I set the (commented out propertie) RESPONSE_SET_STATUS_OVER_SEND_ERROR
Then pact fails like this:
Verifying a pact between consumer and aswsome
Given when organisation with shortName does not exist
Get awsome by isItAwsome:
ul 13, 2017 12:54:14 PM org.glassfish.grizzly.servlet.ServletHandler doServletService
SEVERE: service exception:
javax.servlet.ServletException: javax.servlet.ServletException: java.lang.StringIndexOutOfBoundsException: String index out of range: 0
at org.glassfish.grizzly.servlet.FilterChainImpl.doFilter(FilterChainImpl.java:151)
at org.glassfish.grizzly.servlet.FilterChainImpl.invokeFilterChain(FilterChainImpl.java:106)
at org.glassfish.grizzly.servlet.ServletHandler.doServletService(ServletHandler.java:224)
at org.glassfish.grizzly.servlet.ServletHandler.service(ServletHandler.java:173)
at org.glassfish.grizzly.http.server.HttpHandler$1.run(HttpHandler.java:224)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:593)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:573)
at java.lang.Thread.run(Thread.java:745)
Caused by: javax.servlet.ServletException: java.lang.StringIndexOutOfBoundsException: String index out of range: 0
at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:489)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228)
at org.glassfish.grizzly.servlet.FilterChainImpl.doFilter(FilterChainImpl.java:147)
... 7 more
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: 0
at java.lang.String.charAt(String.java:658)
at org.glassfish.grizzly.http.HttpHeader.isSpecialHeader(HttpHeader.java:925)
at org.glassfish.grizzly.http.HttpHeader.handleGetSpecialHeader(HttpHeader.java:901)
at org.glassfish.grizzly.http.HttpHeader.containsHeader(HttpHeader.java:762)
at org.glassfish.grizzly.http.server.Response.containsHeader(Response.java:1268)
at org.glassfish.grizzly.servlet.HttpServletResponseImpl.containsHeader(HttpServletResponseImpl.java:472)
at org.glassfish.jersey.servlet.internal.ResponseWriter.writeResponseStatusAndHeaders(ResponseWriter.java:159)
at org.glassfish.jersey.server.ServerRuntime$Responder.writeResponse(ServerRuntime.java:683)
at org.glassfish.jersey.server.ServerRuntime$Responder.processResponse(ServerRuntime.java:444)
at org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:434)
at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:329)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473)
... 12 more
returns a response which
has status code 404 (FAILED)
includes headers
"Content-Type" with value "application/json" (FAILED)
has a matching body (FAILED)
Failures:
0) Get organisation by short name returns a response which includes headers "Content-Type" with value "application/json"
Expected header 'Content-Type' to have value 'application/json' but was 'text/html;charset=ISO-8859-1'
1) Get organisation by short name returns a response which has a matching body
comparison -> Expected a response type of 'application/json' but the actual type was 'text/html'
2) Get organisation by short name returns a response which has status code
404
assert expectedStatus == actualStatus
| | |
404 | 500
false
I have the feeling that grizly does not like the Lamda I made for the error handling. But I do not want to change my code just so that I can make my provider work because of he server container. Any ideas I have been trying to debug the code and it flows correctly till it hands it over to the container. And then it seems to ignore the Jersy annotations completely
Upvotes: 1
Views: 768
Reputation: 201
So in the end, the fix feels dirty but it worked. It seems that the grizley container doesnt realy load whole jersy. So in the end I ended up putting the JSON response in my mock like this:
when(awsomeService.getOrganisationByShortName("WME")).thenThrow(new AwsomeRuntimeException(ExceptionStatus.NOT_FOUND,"{\n"
+ " \"timestamp\": 1500040460362,\n" + " \"status\": 404,\n" + " \"error\": \"Not Found\",\n" + " \"message\": \"Not Found\",\n"
+ " \"path\": \"/awsome/isThisAwsome/ABCDE\"\n" + "}"));
Pact seems happy its getting somting like a JSON response it can map to. And I dont have to load more Jersy then I want in the test container. (Witch I coudent figure out).
So all in all this works it doesnt feel fully the richt way but its for a non standard flow so I am ok with it for now.
Upvotes: 0
Reputation: 21
I think your mock isn't setup correctly and that's why you're not handling the right exception. Instead of
when(awsomeService.getOrganisationByShortName("WME")).thenThrow(new AwsomeRuntimeException(ExceptionStatus.NOT_FOUND));
Can you try
when(awsomeService.getOrganisationByShortName(anyString()).thenThrow(new AwsomeRuntimeException(ExceptionStatus.NOT_FOUND));
The line above should fix your mocking behaviour.
Upvotes: 1