Skip to content
Permalink
Browse files
FELIX-6545: add support for http response code constraint checks (#159)
Co-authored-by: Prangish <prangish@Prangishs-MacBook-Pro-2.local>
  • Loading branch information
prangish and Prangish committed Jun 28, 2022
1 parent eb99876 commit f474d8e379c8bd7a604ff4313992f16cad21f218
Showing 2 changed files with 41 additions and 2 deletions.
@@ -89,17 +89,18 @@ public class HttpRequestsCheck implements HealthCheck {

@AttributeDefinition(name = "Request Specs", description = "List of requests to be made. Requests specs have two parts: "
+ "Before '=>' can be a simple URL/path with curl-syntax advanced options (e.g. setting a header with -H \"Test: Test val\"), "
+ "after the '=>' it is a simple response code that can be followed ' && MATCHES <RegEx>' to match the response entity against or other matchers like HEADER, TIME or JSON (see defaults when creating a new configuration for examples).")
+ "after the '=>' it is a simple response code that can be followed ' && MATCHES <RegEx>' to match the response entity against or other matchers like HEADER, TIME, JSON or CODE (see defaults when creating a new configuration for examples).")
String[] requests() default {
"/path/example.html",
"/path/example.html => 200",
"/path/example.html => CODE < 500",
"/protected/example.html => 401",
"-u admin:admin /protected/example.html => 200",
"/path/example.html => 200 && MATCHES <title>html title.*</title>",
"/path/example.html => 200 && MATCHES <title>html title.*</title> && MATCHES anotherRegEx[a-z]",
"/path/example.html => 200 && HEADER Content-Type MATCHES text/html.*",
"/path/example.json => 200 && JSON root.arr[3].prop = myval",
"/path/example-timing-important.html => 200 && TIME < 2000",
"/path/example-timing-important.html => CODE = 200 && TIME < 2000",
"-X GET -H \"Accept: application/javascript\" http://api.example.com/path/example.json => 200 && JSON root.arr[3].prop = myval",
"-X HEAD --data \"{....}\" http://www.example.com/path/to/data.json => 303",
"--proxy proxyhost:2000 /path/example-timing-important.html => 200 && TIME < 2000"
@@ -240,6 +241,8 @@ private void parseResponseAssertion(String responseAssertions) {
for(String clause: responseAssertionArr) {
if(isNumeric(clause)) {
responseChecks.add(new ResponseCodeCheck(Integer.parseInt(clause)));
} else if(clause.toUpperCase().startsWith(ResponseCodeConstraintCheck.CODE)){
responseChecks.add(new ResponseCodeConstraintCheck(clause.substring(ResponseCodeConstraintCheck.CODE.length())));
} else if(clause.toUpperCase().startsWith(ResponseTimeCheck.TIME)) {
responseChecks.add(new ResponseTimeCheck(clause.substring(ResponseTimeCheck.TIME.length())));
} else if(clause.toUpperCase().startsWith(ResponseEntityRegExCheck.MATCHES)) {
@@ -505,6 +508,27 @@ public ResponseCheckResult checkResponse(Response response, FormattingResultLog
}
}

static class ResponseCodeConstraintCheck implements ResponseCheck {
final static String CODE = "CODE ";
private final String codeConstraint;
private final SimpleConstraintChecker simpleConstraintChecker;

public ResponseCodeConstraintCheck(String codeConstraint) {
this.codeConstraint = codeConstraint;
this.simpleConstraintChecker = new SimpleConstraintChecker();
}

@Override
public ResponseCheckResult checkResponse(Response response, FormattingResultLog log) {

if(!simpleConstraintChecker.check(response.actualResponseCode, codeConstraint)) {
return new ResponseCheckResult(true, "code [" + response.actualResponseCode + "] does not fulfil constraint ["+codeConstraint+"]");
} else {
return new ResponseCheckResult(false, "code ["+response.actualResponseCode + "] fulfils constraint ["+codeConstraint+"]");
}
}
}

static class ResponseTimeCheck implements ResponseCheck {
final static String TIME = "TIME ";

@@ -151,6 +151,21 @@ private void assertTimeConstraint(long time, String constraint, boolean expected
ResponseCheckResult checkResult = responseTimeCheck.checkResponse(response, log);
assertEquals("Expected "+expectedTrueOrFalse + " for expression ["+constraint+"] against json: "+time+"ms", expectedTrueOrFalse, !checkResult.contraintFailed);
}

@Test
public void testCodeConstraint() {
assertCodeConstraint(200, "< 500", true);
assertCodeConstraint(403, "between 200 and 500", true);
assertCodeConstraint(503, "< 500", false);
assertCodeConstraint(201, "= 201", true);
}

private void assertCodeConstraint(int code, String constraint, boolean expectedTrueOrFalse) {
HttpRequestsCheck.ResponseCodeConstraintCheck responseTimeCheck = new HttpRequestsCheck.ResponseCodeConstraintCheck(constraint);
HttpRequestsCheck.Response response = new HttpRequestsCheck.Response(code, "OK", null, "", 1000);
ResponseCheckResult checkResult = responseTimeCheck.checkResponse(response, log);
assertEquals("Expected "+expectedTrueOrFalse + " for expression ["+constraint+"] against json: "+code, expectedTrueOrFalse, !checkResult.contraintFailed);
}

@Test
public void testSplitArgsRespectingQuotes() throws Exception {

0 comments on commit f474d8e

Please sign in to comment.