Skip to content

Commit 83eccca

Browse files
Merge pull request #20 from group-15-dd2480/feat/response-status-text
Feat/response status text (#5, #6)
2 parents 34cb19f + 90c085e commit 83eccca

16 files changed

+97
-16
lines changed

karate-core/src/main/java/com/intuit/karate/Actions.java

+2
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ public interface Actions {
135135

136136
void status(int status);
137137

138+
void statusText(String text);
139+
138140
void table(String name, List<Map<String, String>> table);
139141

140142
void text(String name, String exp);

karate-core/src/main/java/com/intuit/karate/ScenarioActions.java

+6
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,12 @@ public void status(int status) {
302302
engine.status(status);
303303
}
304304

305+
@Override
306+
@When("^status text (.+)")
307+
public void statusText(String text) {
308+
engine.statusText(text);
309+
}
310+
305311
@Override
306312
@When("^match (.+)(=|contains|any|only|deep)(.*)")
307313
public void match(String exp, String op1, String op2, String rhs) {

karate-core/src/main/java/com/intuit/karate/core/MockHandler.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -188,20 +188,22 @@ public synchronized Response handle(Request req) { // note the [synchronized]
188188
Scenario scenario = fs.getScenario();
189189
if (isMatchingScenario(scenario, engine)) {
190190
Map<String, Object> configureHeaders;
191-
Variable response, responseStatus, responseHeaders, responseDelay;
191+
Variable response, responseStatus, responseStatusText, responseHeaders, responseDelay;
192192
ScenarioActions actions = new ScenarioActions(engine);
193193
Result result = executeScenarioSteps(feature, runtime, scenario, actions);
194194
engine.mockAfterScenario();
195195
configureHeaders = engine.mockConfigureHeaders();
196196
response = engine.vars.remove(ScenarioEngine.RESPONSE);
197197
responseStatus = engine.vars.remove(ScenarioEngine.RESPONSE_STATUS);
198+
responseStatusText = engine.vars.remove(ScenarioEngine.RESPONSE_STATUS_TEXT);
198199
responseHeaders = engine.vars.remove(ScenarioEngine.RESPONSE_HEADERS);
199200
responseDelay = engine.vars.remove(RESPONSE_DELAY);
200201
globals.putAll(engine.shallowCloneVariables());
201-
Response res = new Response(200);
202+
Response res = new Response(200, "OK");
202203
if (result.isFailed()) {
203204
response = new Variable(result.getError().getMessage());
204205
responseStatus = new Variable(500);
206+
responseStatusText = new Variable("Internal Server Error");
205207
} else {
206208
if (corsEnabled) {
207209
res.setHeader("Access-Control-Allow-Origin", "*");
@@ -226,6 +228,9 @@ public synchronized Response handle(Request req) { // note the [synchronized]
226228
if (responseStatus != null) {
227229
res.setStatus(responseStatus.getAsInt());
228230
}
231+
if (responseStatusText != null) {
232+
res.setStatusText(responseStatusText.getAsString());
233+
}
229234
if (prevEngine != null) {
230235
ScenarioEngine.set(prevEngine);
231236
}

karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java

+9
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ public class ScenarioEngine {
7171
public static final String RESPONSE = "response";
7272
public static final String RESPONSE_HEADERS = "responseHeaders";
7373
public static final String RESPONSE_STATUS = "responseStatus";
74+
public static final String RESPONSE_STATUS_TEXT = "responseStatusText";
7475
private static final String RESPONSE_BYTES = "responseBytes";
7576
private static final String RESPONSE_COOKIES = "responseCookies";
7677
private static final String RESPONSE_TIME = "responseTime";
@@ -650,6 +651,7 @@ private void httpInvokeOnce() {
650651
setHiddenVariable(REQUEST_TIME_STAMP, startTime);
651652
setVariable(RESPONSE_TIME, responseTime);
652653
setVariable(RESPONSE_STATUS, response.getStatus());
654+
setVariable(RESPONSE_STATUS_TEXT, response.getStatusText());
653655
setVariable(RESPONSE, body);
654656
if (config.isLowerCaseResponseHeaders()) {
655657
setVariable(RESPONSE_HEADERS, response.getHeadersWithLowerCaseNames());
@@ -718,6 +720,13 @@ public void status(int status) {
718720
}
719721
}
720722

723+
public void statusText(String text) {
724+
if (!text.equals(response.getStatusText())) {
725+
String message = HttpLogger.getStatusTextFailureMessage(text, config, httpRequest, response);
726+
setFailedReason(new KarateException(message));
727+
}
728+
}
729+
721730
public KeyStore getKeyStore(String trustStoreFile, String password, String type) {
722731
if (trustStoreFile == null) {
723732
return null;

karate-core/src/main/java/com/intuit/karate/http/ApacheHttpClient.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ public Response invoke(HttpRequest request) {
307307
}
308308
}
309309
int statusCode = httpResponse.getStatusLine().getStatusCode();
310+
String statusMessage = httpResponse.getStatusLine().getReasonPhrase();
310311
Map<String, List<String>> headers = toHeaders(httpResponse);
311312
List<Cookie> storedCookies = cookieStore.getCookies();
312313
Header[] requestCookieHeaders = httpResponse.getHeaders(HttpConstants.HDR_SET_COOKIE);
@@ -341,7 +342,7 @@ public Response invoke(HttpRequest request) {
341342
}
342343
headers.put(HttpConstants.HDR_SET_COOKIE, mergedCookieValues);
343344
cookieStore.clear();
344-
Response response = new Response(statusCode, headers, bytes);
345+
Response response = new Response(statusCode, statusMessage, headers, bytes);
345346
httpLogger.logResponse(getConfig(), request, response);
346347
return response;
347348
}

karate-core/src/main/java/com/intuit/karate/http/ArmeriaHttpClient.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public Response invoke(HttpRequest request) {
102102
}
103103
}
104104
byte[] responseBody = ahr.content().isEmpty() ? Constants.ZERO_BYTES : ahr.content().array();
105-
Response response = new Response(ahr.status().code(), responseHeaders, responseBody);
105+
Response response = new Response(ahr.status().code(), ahr.status().codeAsText(), responseHeaders, responseBody);
106106
httpLogger.logResponse(config, request, response);
107107
return response;
108108
}

karate-core/src/main/java/com/intuit/karate/http/AwsLambdaHandler.java

+2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public class AwsLambdaHandler {
5757
private static final String BODY = "body";
5858
private static final String IS_BASE64_ENCODED = "isBase64Encoded";
5959
private static final String STATUS_CODE = "statusCode";
60+
private static final String STATUS_CODE_TEXT = "statusCodeText";
6061

6162
private final ServerHandler handler;
6263

@@ -102,6 +103,7 @@ public void handle(InputStream in, OutputStream out) throws IOException {
102103
Response response = handler.handle(request);
103104
Map<String, Object> res = new HashMap(4);
104105
res.put(STATUS_CODE, response.getStatus());
106+
res.put(STATUS_CODE_TEXT, response.getStatusText());
105107
Map<String, List<String>> responseHeaders = response.getHeaders();
106108
if (responseHeaders != null) {
107109
Map<String, String> temp = new HashMap(responseHeaders.size());

karate-core/src/main/java/com/intuit/karate/http/HttpLogger.java

+14
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,20 @@ public static String getStatusFailureMessage(int expected, Config config, HttpRe
113113
+ ", response: \n" + rawResponse;
114114
}
115115

116+
public static String getStatusTextFailureMessage(String expected, Config config, HttpRequest request, Response response) {
117+
String url = request.getUrl();
118+
HttpLogModifier logModifier = logModifier(config, url);
119+
String maskedUrl = logModifier == null ? url : logModifier.uri(url);
120+
String rawResponse = response.getBodyAsString();
121+
if (rawResponse != null && logModifier != null) {
122+
rawResponse = logModifier.response(url, rawResponse);
123+
}
124+
long responseTime = request.getEndTime() - request.getStartTime();
125+
return "status text was: " + response.getStatusText() + ", expected: " + expected
126+
+ ", response time in milliseconds: " + responseTime + ", url: " + maskedUrl
127+
+ ", response: \n" + rawResponse;
128+
}
129+
116130
public void logRequest(Config config, HttpRequest request) {
117131
requestCount++;
118132
String uri = request.getUrl();

karate-core/src/main/java/com/intuit/karate/http/RequestCycle.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ protected Response handle() {
175175
if (valid == null || !valid) {
176176
logger.error("unauthorized request: {}", request);
177177
response.setStatus(401); // just for logging in finally block
178-
return response().buildWithStatus(401);
178+
return response().buildWithStatus(401, "Unauthorized");
179179
}
180180
}
181181
if (context.isApi()) {
@@ -194,7 +194,7 @@ protected Response handle() {
194194
} catch (Exception e) {
195195
logger.error("handle failed: {}", e.getMessage());
196196
response.setStatus(500); // just for logging in finally block
197-
return response().buildWithStatus(500);
197+
return response().buildWithStatus(500, "Internal Server Error");
198198
} finally {
199199
close();
200200
if (logger.isDebugEnabled()) {

karate-core/src/main/java/com/intuit/karate/http/RequestHandler.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ public Response handle(Request request) {
114114
} else {
115115
rb.locationHeader(signInPath());
116116
}
117-
return rb.buildWithStatus(302);
117+
return rb.buildWithStatus(302, "Found");
118118
}
119119
}
120120
}

karate-core/src/main/java/com/intuit/karate/http/Response.java

+30-5
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,24 @@ public class Response implements ProxyObject {
5252

5353
private static final Logger logger = LoggerFactory.getLogger(Response.class);
5454

55-
public static final Response OK = new Response(200);
55+
public static final Response OK = new Response(200, "OK");
5656

5757
private static final String BODY = "body";
5858
private static final String BODY_BYTES = "bodyBytes";
5959
private static final String STATUS = "status";
60+
private static final String STATUS_TEXT = "statusText";
6061
private static final String HEADER = "header";
6162
private static final String HEADERS = "headers";
6263
private static final String HEADER_VALUES = "headerValues";
6364
private static final String DATA_TYPE = "dataType";
6465
private static final String RESPONSE_TIME = "responseTime";
6566

66-
private static final String[] KEYS = new String[]{STATUS, HEADER, HEADERS, HEADER_VALUES, BODY, DATA_TYPE, BODY_BYTES, RESPONSE_TIME};
67+
private static final String[] KEYS = new String[]{STATUS, STATUS_TEXT, HEADER, HEADERS, HEADER_VALUES, BODY, DATA_TYPE, BODY_BYTES, RESPONSE_TIME};
6768
private static final Set<String> KEY_SET = new HashSet(Arrays.asList(KEYS));
6869
private static final JsArray KEY_ARRAY = new JsArray(KEYS);
6970

7071
private int status;
72+
private String statusText;
7173
private Map<String, List<String>> headers;
7274
private Object body;
7375

@@ -76,15 +78,21 @@ public class Response implements ProxyObject {
7678
private long responseTime;
7779

7880
public Response(int status) {
81+
this(status, null);
82+
}
83+
84+
public Response(int status, String statusText) {
7985
this.status = status;
86+
this.statusText = statusText;
8087
}
8188

82-
public Response(int status, Map<String, List<String>> headers, byte[] body) {
83-
this(status, headers, body, null);
89+
public Response(int status, String statusText, Map<String, List<String>> headers, byte[] body) {
90+
this(status, statusText, headers, body, null);
8491
}
8592

86-
public Response(int status, Map<String, List<String>> headers, byte[] body, ResourceType resourceType) {
93+
public Response(int status,String statusText, Map<String, List<String>> headers, byte[] body, ResourceType resourceType) {
8794
this.status = status;
95+
this.statusText = statusText;
8896
this.headers = headers;
8997
this.body = body;
9098
this.resourceType = resourceType;
@@ -98,6 +106,14 @@ public void setStatus(int status) {
98106
this.status = status;
99107
}
100108

109+
public String getStatusText() {
110+
return statusText;
111+
}
112+
113+
public void setStatusText(String statusText) {
114+
this.statusText = statusText;
115+
}
116+
101117
public int getDelay() {
102118
return delay;
103119
}
@@ -253,6 +269,8 @@ public Object getMember(String key) {
253269
switch (key) {
254270
case STATUS:
255271
return status;
272+
case STATUS_TEXT:
273+
return statusText;
256274
case HEADER:
257275
return HEADER_FUNCTION;
258276
case HEADERS:
@@ -284,6 +302,7 @@ public Object getMember(String key) {
284302
public Map<String, Object> toMap() {
285303
Map<String, Object> map = new HashMap();
286304
map.put(STATUS, status);
305+
map.put(STATUS_TEXT, statusText);
287306
map.put(HEADERS, JsonUtils.simplify(headers));
288307
map.put(BODY, getBodyConverted());
289308
map.put(RESPONSE_TIME, responseTime);
@@ -309,6 +328,9 @@ public void putMember(String key, Value value) {
309328
case STATUS:
310329
status = value.asInt();
311330
break;
331+
case STATUS_TEXT:
332+
statusText = value.asString();
333+
break;
312334
case HEADERS:
313335
setHeaders((Map) JsValue.toJava(value));
314336
break;
@@ -321,6 +343,9 @@ public void putMember(String key, Value value) {
321343
public String toString() {
322344
StringBuilder sb = new StringBuilder();
323345
sb.append("[status: ").append(status);
346+
if (statusText != null) {
347+
sb.append(", text: ").append(statusText);
348+
}
324349
sb.append(", responseTime: ").append(responseTime);
325350
if (resourceType != null && resourceType != ResourceType.BINARY) {
326351
sb.append(", type: ").append(resourceType);

karate-core/src/main/java/com/intuit/karate/http/ResponseBuilder.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ public Response build() {
181181
}
182182
}
183183
}
184-
return buildWithStatus(response.getStatus());
184+
return buildWithStatus(response.getStatus(), response.getStatusText());
185185
}
186186

187187
private static byte[] merge(byte[] body, byte[] extra) {
@@ -211,11 +211,11 @@ public Response buildStatic(Request request) { // TODO ETag header handling
211211
} catch (Exception e) {
212212
logger.error("local resource failed: {} - {}", request, e.toString());
213213
}
214-
return buildWithStatus(200);
214+
return buildWithStatus(200, "OK");
215215
}
216216

217-
public Response buildWithStatus(int status) {
218-
return new Response(status, headers, status == 204 ? null : body, resourceType);
217+
public Response buildWithStatus(int status, String statusText) {
218+
return new Response(status, statusText, headers, status == 204 ? null : body, resourceType);
219219
}
220220

221221
}

karate-core/src/test/java/com/intuit/karate/core/MockHandlerTest.java

+13
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,19 @@ void testResponseStatus() {
188188
match(response.getBodyConverted(), "{ success: false }");
189189
match(response.getStatus(), 404);
190190
}
191+
192+
@Test
193+
void testResponseStatusText() {
194+
background().scenario(
195+
"pathMatches('/hello')",
196+
"def response = { success: false }",
197+
"def responseStatusText = 'Not Found'"
198+
);
199+
request.path("/hello");
200+
handle();
201+
match(response.getBodyConverted(), "{ success: false }");
202+
match(response.getStatusText(), "Not Found");
203+
}
191204

192205
@Test
193206
void testResponseHeaders() {

karate-core/src/test/java/com/intuit/karate/core/mock/hello-world.feature

+2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ Given url mockServerUrl + 'cats'
1111
And request { name: 'Billie' }
1212
When method postMethod
1313
Then status 201
14+
And status text Created
1415
And match response == { id: '#ignore', name: 'Billie' }
1516
# And assert responseTime < 1000
1617

1718
Given path response.id
1819
When method getMethod
1920
Then status 200
21+
And status text OK

karate-core/src/test/java/com/intuit/karate/core/mock/patch.feature

+1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ And path 'patch'
77
And request { foo: 'bar' }
88
When method patch
99
Then status 422
10+
And status text Unprocessable Entity
1011
And match response == { success: true }

karate-demo/src/test/java/demo/cats/cats.feature

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Given path 'cats'
1212
And request { name: 'Billie' }
1313
When method post
1414
Then status 200
15+
And status text
1516
And match response == { id: '#number', name: 'Billie' }
1617

1718
* def id = response.id

0 commit comments

Comments
 (0)