I am new to Jmeter and am looking for a way to send emails out for every failed assertion.
Test Structure:
Thread Group:
Transaction Controller:
Http Request:
Http Request:
Http Request:
Thread Group:
Transaction Controller:
Http Request:
Http Request:
Http Request:
Each Http request contains a response assertion. I would like to capture and send one email that contains all of the failed assertions within a transaction controller. Is there a way to do this? I tried using adding a SMTP Sampler within a thread group with a child Bean PreProcessor that contains this code:
import org.apache.jmeter.assertions.AssertionResult;
try {
AssertionResult[] results = prev.getAssertionResults();
StringBuilder body = new StringBuilder();
for (AssertionResult result : results) {
body.append(result.getName());
body.append(result.getFailureMessage());
body.append(System.getProperty("line.separator"));
}
vars.put("body", body.toString());
}
catch (Throwable ex) {
log.error("Error in Beanshell", ex);
throw ex;
}
When i do this it will only send an email of the last failed assertion instead of all failed assertions.
Add a global JSR223 Listener (it is much better to use Groovy rather than Beanshell, see Groovy is the New Black article for details)
Put the following code into "Script" area (it is basically your code but amended to read previous samplers results from the ${body} variable and append new results to them
import org.apache.jmeter.assertions.AssertionResult;
try {
AssertionResult[] results = prev.getAssertionResults();
StringBuilder body = new StringBuilder();
String previousBody = vars.get("body");
if (previousBody != null) {
body.append(previousBody);
}
for (AssertionResult result : results) {
body.append(result.getName());
body.append(result.getFailureMessage());
body.append(System.getProperty("line.separator"));
}
vars.put("body", body.toString());
} catch (Throwable ex) {
log.error("Error in Groovy", ex);
throw ex;
}
We have a test that prints out request body information to the console on failure. This is added to each sampler individually and works quite nicely. You could update this code send a failure message instead of printing to the console.
//Loop through assertions and check for failed
for (int i = 0; i < results.length; i++){
if (results[i].isFailure() || results[i].isError()){
failed_assertion = true;
System.out.println("\n********** Request Body ***************\n"+ctx.getCurrentSampler().getUrl().getPath()+ctx.getCurrentSampler().getQueryString()+'\n'+ctx.getCurrentSampler().getArguments().getArgument(0).getValue()+"\n");
System.out.println("************ ERROR DETECTED ***********\n"+prev.getResponseDataAsString()+"\n****************************************\n");
break;
}
}
If that doesn't work you could construct an IF block on each sampler. Similar to what they're doing here.
Related
Why can not I read bytes from the TcpClient in C#?
Here is the error I am getting:
Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.
Here is how I start my TcpClient:
public static async void Start()
{
TcpListener server = null;
try
{
server = new TcpListener(IPAddress.Loopback, 13000);
server.Start();
var client = await server.AcceptTcpClientAsync();
var stream = client.GetStream();
var bytes = Convert.FromBase64String("ABCD");
await stream.WriteAsync(bytes, 0, bytes.Length);
client.Close();
}
catch (Exception e)
{
throw;
}
finally
{
if(server != null)
{
server.Stop();
}
}
}
Here is how I run a request to the TcpClient:
try {
var response = (new HttpClient()).GetByteArrayAsync("http://localhost:13000").Result;
return Convert.ToBase64String(response);
} catch(Exception e) {
throw;
}
The return Convert.ToBase64String(response); line is never reached. While I see the quoted above error message inside the Exception e if I hit a breakpoint on the throw line.
Also, during debug the Start() method completes just fine. I.e. it starts, then wait for a request, gets a request, writes to the TclClient and at the end runs the server.Stop(); command.
I am expecting my code to work, because I took it and modified from the official documentation over here.
I tried to check out a few resources which would tackle my exception, but none of them did help.
E.g. I tried to use the question.
First answer tells nothing useful actually, but just plays around with words and at the end states that one can do nothing about the exception (please, correct me if I am missing a point in the answer).
And the second answer tells an impossible in my case problem. Because, I am sure there is nothing running on the 13000 port.
Your client code is using HttpClient, which sends an HTTP request and expects an HTTP response. But your server is not an HTTP server, it is just a plain TCP server, so the client is likely to fail and forcibly close the connection when it doesn't receive a properly formatted HTTP response.
The "official documentation" whose example you modified is not using HttpClient at all, it is using TcpClient instead.
If you want to use HttpClient in your client, then you should use HttpListener instead of TcpListener in your server.
I'm new to MSF4J and I need to write a REST API that accepts a large XML data through POST. I am using
request.getMessegeBody()
method to get the data. I discovered that it's now deprecated but I couldn't find the newer version of it so I decided to use it anyway.
The problem is, when I send data to the microservice for the first time, it doesn't get the whole data. All the subsequent requests will get the full message body except the first.
When I try passing the request through ESB, ESB receives the whole body but when it reaches the endpoint it will be truncated.
I have also tried sending requests from different rest clients but for the first time it always gets the incomplete message body
#POST
#Consumes({ "application/xml", "application/json", "text/xml" })
#Path("test/")
public Response getReqNotification(#Context Request request) throws Exception {
Response.ResponseBuilder respBuilder =
Response.status(Response.Status.OK).entity(request);
ByteBuf b = request.getMessageBody();
byte[] bb = new byte[b.readableBytes()];
b.duplicate().readBytes(bb);
System.out.println(new String(bb));
return respBuilder.build();
}
I expect it to print the full message(which is about 2000 bytes long) every time when I send a request, but I'm only getting around 800 bytes when I first run the microservice.
I hope ill get assistance here. I have tried elsewhere but wso2 doesn't have much documentation (⌣_⌣”)
I still don't really understand what I was doing wrong but with the help of this link I have managed to come up with the following code and it works fine.
The major cha is that I now use request.getMessageContentStream() instead of the depricated request.getMessageBody()
#Consumes({ "application/xml", "application/json", "text/xml" })
#Path("test/")
public Response getReqNotification(#Context Request request) throws Exception {
Response.ResponseBuilder respBuilder =
Response.status(Response.Status.OK).entity(request);
String data = "";
BufferedInputStream bis = new BufferedInputStream(request.getMessageContentStream());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
int d;
while ((d = bis.read()) != -1) {
bos.write(d);
}
data = bos.toString();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
}
}
System.out.println(data);
//////do stuff
return respBuilder.build();
}
I am trying to learn how to handle exception in APIs servers so I followed this where he has built API for birds, he finally reached to APIs like this:
#GetMapping(value = "/params")
public Bird getBirdRequestParam(#RequestParam("birdId") Long birdId) throws EntityNotFoundException {
Bird bird = birdRepository.findOne(birdId);
if(bird == null){
throw new EntityNotFoundException(Bird.class, "id", birdId.toString());
}
return bird;
}
and the ControllerAdvice has a method:
#ExceptionHandler(EntityNotFoundException.class)
protected ResponseEntity<Object> handleEntityNotFound(
EntityNotFoundException ex) {
ApiError apiError = new ApiError(NOT_FOUND);
apiError.setMessage(ex.getMessage());
return buildResponseEntity(apiError);
}
the response will be a bird like this
{
"id": 1,
"scientificName": "Atlantic canary",
"specie": "serinus canaria",
"mass": 10,
"length": 11
}
or an exception details like this:
{
"apierror": {
"status": "NOT_FOUND",
"timestamp": "09-04-2018 10:11:44",
"message": "Bird was not found for parameters {id=2}"
}
but the problem is with my server that contacts with API
I am using :
public void gett(#RequestParam Long id) {
ResponseEntity<Bird> responseEntity = restTemplate.getForEntity("http://localhost:8181/params" + id, Bird.class);
bird = responseEntity.getBody();
model.addAttribute("birdform", bird);
return "bird";
}
the getForEntity is waiting for a response with bird body but an exception may be thrown in server and the response may be json of the error.
how to handle this problem in my client server?
in other words :
how to know in my client server that the api server has thrown an exception in json form.???
I have tried to get the response in "Object" variable and then try to know if it was excption or bird with "instance of" expression like this code
#GetMapping("/getbird")
public String getAll(#RequestParam Long id, Model model) {
ResponseEntity<Object> responseEntity = restTemplate.getForEntity("http://localhost:8181/api/bird/getone?id=" + id, Object.class);
if (responseEntity.getBody() instanceof Bird.class) {
Bird bird= (Bird) responseEntity.getBody();
model.addAttribute("Bird", bird);
return "bird-form";
}
else{
// something else
return "someview";
}
}
but first thing it didnot work (the instance of always return false)
the second thing is that this is a hard work to do with all my controllers' actions.
I hope that i could explain my problem clearly .
thanks....
You don't need to check the body of the response to see if you got an error. restTemplate.getForEntity() (and other methods) would throw an HttpClientErrorException if you get a 4XX response, or HttpServerErrorException if you get a 5XX response from the call.
To catch these exceptions, you can define a #ControllerAdvice with proper methods for exception handling:
#ControllerAdvice
class GlobalControllerExceptionHandler {
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) // 500
#ExceptionHandler(HttpClientErrorException.class)
public ApiError handle4xxFromClient(HttpClientErrorException ex) {
// construct and return a custom ApiError object
}
}
See https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc for details.
Two solutions :
Use a custom implementation error handler in your reste template.
restTemplate.setErrorHandler(customerErrorHandler)
Use the http status, rest template will throw an exception if it gets a bad http status from the server it is querying. Catch the exception and get the ApiError Object from the exception, and then throw and exception of your own that will be handled by your exception handler in your client server.
For these solutions to work, the server your are querying needs to send the right http status code when something wrong happens.
I am exposing a rest service using "CamelHttpTransportServlet" that receive orders and place in jms queue. The code works fine on happy path and returns 200 response.
I have written Processor to validate the input JSON, and set http_response_code based on the input.
The issue is - for invalid requests though failure response code - 400 is set, the flow continues to the next route and pushes the data to the queue instead of sending the 400 response back to the calling app.
rest("/ordermanagement")
.post("/order").to("direct:checkInput");
from("direct:checkInput")
.process(new Processor() {
#Override
public void process(final Exchange exchange) throws Exception {
String requestBody = exchange.getIn().getBody(String.class);
if(requestBody == "" || requestBody== null) {
exchange.getIn().setBody("{ "error": Bad Request}");
exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "application/json");
exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
}
}
})
.to("direct:sendToQ");
from("direct:sendToQ")
.to("jms:queue:orderReceiver")
.log("Sent to JMS");
Can someone advise what is missing here and provide a sample if possible?
Trying to implement onException approach:
rest("/ordermanagement")
.post("/order").to("direct:checkInput");
onException(CustomException.class).handled(true)
.setHeader(Exchange.HTTP_RESPONSE_CODE, code)
.setBody(jsonObject);
from("direct:checkInput")
.process(new Processor() {
#Override
public void process(final Exchange exchange) throws Exception {
String requestBody = exchange.getIn().getBody(String.class);
if(requestBody == "" || requestBody== null) {
throw CustomException(code, jsonObject)
}
}
})
.to("direct:sendToQ");
from("direct:sendToQ")
.to("jms:queue:orderReceiver")
.log("Sent to JMS");
However I could not figure out how to pass the parameters - code,jsonObject from processor to onException block.
Any help on this? Is this feasible?
I'd use something along the lines of the code example below:
onException(CustomException.class)
.handled(true)
.bean(PrepareErrorResponse.class)
.log("Error response processed");
rest("/ordermanagement")
.post("/order")
.to("direct:checkInput");
from("direct:checkInput")
.process((Exchange exchange) -> {
String requestBody = exchange.getIn().getBody(String.class);
if(requestBody == "" || requestBody== null) {
throw new CustomException(code, jsonObject);
}
})
.to("direct:sendToQ");
from("direct:sendToQ")
.to("jms:queue:orderReceiver")
.log("Sent to JMS");
Camel will store any exception caught in the exchange's property and should be therefore obtainable via the Exchange.EXCEPTION_CAUGHT property key. The sample below illustrates how such a custom error message bean can look like:
public class PrepareErrorResponse {
#Handler
public void prepareErrorResponse(Exchange exchange) {
Throwable cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Throwable.class);
if (cause instanceof CustomException) {
CustomException validationEx = (CustomException) cause;
// ...
}
Message msg = exchange.getOut();
msg.setHeader(Exchange.CONTENT_TYPE, MediaType.APPLICATION_JSON);
msg.setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
JsonObject errorMessage = new JsonObject();
errorMessage.put("error", "Bad Request");
errorMessage.put("reason", cause.getMessage());
msg.setBody(errorMessage.toString());
// we need to do the fault=false below in order to prevent a
// HTTP 500 error code from being returned
msg.setFault(false);
}
}
Camel provides a couple of ways actually to deal with exceptions. The presented way here is just one example. The proposed code however allows to use custom redelivery strategies for different caught exceptions as well as additional stuff. If the error could get resolved within the exception handler, the route is proceeded at the point the exception occurred (i.e. temporary network issue with a redelivery strategy applied). If the error could not get fixed within the handler, the exchange will be stopped. Usually one would then send the currently processed message to a DLQ and log something about the error.
Note that this example will assume that CustomException is an unchecked exception as the processor is replaced with a simpler lambda. If you can't or don't want to use such an exception (or lambda expressions) replace the lambda-processor with new Processor() { #Override public void process(Exchange exchange) throws Exception { ... } } construct.
Here is one way to do it. You can use choice
rest("/ordermanagement")
.post("/order").to("direct:checkInput");
from("direct:checkInput")
.process(exchange -> {
String requestBody = exchange.getIn().getBody(String.class);
if(requestBody == null || requestBody.equals("")) {
exchange.getIn().setBody("{ "error": Bad Request}");
exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "application/json");
exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
}
})
.choice()
.when(exchange -> {
Object header = exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE);
return header != null && header.equals(400);
})
.stop()
.otherwise()
.to("direct:sendToQ")
.endChoice();
from("direct:sendToQ")
.to("jms:queue:orderReceiver")
.log("Sent to JMS");
Setting ROUTE_STOP property to true in the processor should prevent further flow and return your response:
...
exchange.getIn().setBody("{ "error": Bad Request}");
exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "application/json");
exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
exchange.setProperty(Exchange.ROUTE_STOP, Boolean.TRUE);
...
I'm using WSS4j CXF Out Interceptor in MULE to sign the SOAP response but if there is an error in this interceptor the SOAPFault is not generated properly. In fact the result is a blank body with status 200.
Problem:
If the out interceptor used to sign (WSS4JOutInterceptor) fails, it does not generates a proper SOAPFault (with status code 400/500) due to is executed in PRE_PROTOCOL and the http.status and response headers have already been written in the HttpResponse.
Cause
The SOAPFault is generated in a last phase in the interceptor chain (interceptor chain) so the HttpConnection is already open and the HttpResponse is being written, headers and status are set.
Detail
Mule version: 3.6.1 CE
CXF version: 2.5.9
WSS4j: 1.6.9
JVM: JDK7
The CXF inbound enpoint in mule calls to CxfInboundMessageProcessor. This class create the Exchange to execute the input interceptor chain , the mule flow and finally the output interceptor chain .
The most important phases that causes this error are the following:
PREPARE_SEND Opening of the connection
PRE_STREAM
PRE_PROTOCOL Misc protocol actions.->Here is executed *WSS4jOutInterceptor**
The output interceptor chain is executed in two phases, the mule interceptor MuleProtocolHeadersOutInterceptor (PRE_STREAM) pauses it. The rest of the output interceptor chain is executed when the HttpResponse is fully created.
When it is paused the execution return back to the first class CxfInboundMessageProcessor.
it is after that when the response is going to be created:
MuleMessage muleResMsg = responseEvent.getMessage();
muleResMsg.setPayload(getResponseOutputHandler(m));
The interface org.mule.api.transport.OutputHandler is used to delegate the SOAP object creation until the org.mule.transport.http.ResponseWriter is executed:
OutputHandler:
Here it can see how the method write continues with the output chain:
public void write(MuleEvent event, OutputStream out) throws IOException
{
Message outFaultMessage = m.getExchange().getOutFaultMessage();
Message outMessage = m.getExchange().getOutMessage();
Message contentMsg = null;
if (outFaultMessage != null && outFaultMessage.getContent(OutputStream.class) != null)
{
contentMsg = outFaultMessage;
}
else if (outMessage != null)
{
contentMsg = outMessage;
}
if (contentMsg == null)
{
return;
}
DelegatingOutputStream delegate = contentMsg.getContent(DelegatingOutputStream.class);
if (delegate.getOutputStream() instanceof ByteArrayOutputStream)
{
out.write(((ByteArrayOutputStream) delegate.getOutputStream()).toByteArray());
}
delegate.setOutputStream(out);
out.flush();
contentMsg.getInterceptorChain().resume();
}
org.mule.transport.http.HttpServerConnection
public void writeResponse(final HttpResponse response, Map<String,String> headers) throws IOException
{
if (response == null)
{
return;
}
if (!response.isKeepAlive())
{
Header header = new Header(HttpConstants.HEADER_CONNECTION, "close");
response.setHeader(header);
}
setKeepAlive(response.isKeepAlive());
addHeadersToHttpResponse(response, headers);
ResponseWriter writer = new ResponseWriter(this.out, encoding);
OutputStream outstream = this.out;
writer.println(response.getStatusLine());
Iterator item = response.getHeaderIterator();
while (item.hasNext())
{
Header header = (Header) item.next();
writer.print(header.toExternalForm());
}
writer.println();
writer.flush();
OutputHandler content = response.getBody();
if (content != null)
{
Header transferenc = response.getFirstHeader(HttpConstants.HEADER_TRANSFER_ENCODING);
if (transferenc != null)
{
response.removeHeaders(HttpConstants.HEADER_CONTENT_LENGTH);
if (transferenc.getValue().indexOf(HttpConstants.TRANSFER_ENCODING_CHUNKED) != -1)
{
outstream = new ChunkedOutputStream(outstream);
}
}
content.write(RequestContext.getEvent(), outstream);
if (outstream instanceof ChunkedOutputStream)
{
((ChunkedOutputStream) outstream).finish();
}
}
outstream.flush();
}
And here after httpResponse creation and set the headers is when the "body" is generated: