Add support for headers in REST tests

This adds support for arbitrary headers sent with each REST request, it
will allow us to test things like different xcontent-encoding (see
50_with_headers.yaml for what this looks like).

Headers are specified at the same level as `catch`, so a request would
look like:

```yaml
- do:
    headers:
      Content-Type: application/yaml
    get:
      index: test_1
      type:  _all
      id:    1
```
This commit is contained in:
Lee Hinman 2015-11-24 08:22:20 -07:00
parent 18a8c20cba
commit a25b407aeb
8 changed files with 106 additions and 16 deletions

View File

@ -0,0 +1,30 @@
---
"REST test with headers":
- skip:
features: headers
- do:
index:
index: test_1
type: test
id: 1
body: { "body": "foo" }
- do:
headers:
Content-Type: application/yaml
get:
index: test_1
type: _all
id: 1
- match:
$body: |
/^---\n
_index:\s+\"test_1"\n
_type:\s+"test"\n
_id:\s+"1"\n
_version:\s+1\n
found:\s+true\n
_source:\n
\s+body:\s+"foo"\n$/

View File

@ -62,7 +62,8 @@ public class RestTestExecutionContext implements Closeable {
* Saves the obtained response in the execution context.
* @throws RestException if the returned status code is non ok
*/
public RestResponse callApi(String apiName, Map<String, String> params, List<Map<String, Object>> bodies) throws IOException, RestException {
public RestResponse callApi(String apiName, Map<String, String> params, List<Map<String, Object>> bodies,
Map<String, String> headers) throws IOException, RestException {
//makes a copy of the parameters before modifying them for this specific request
HashMap<String, String> requestParams = new HashMap<>(params);
for (Map.Entry<String, String> entry : requestParams.entrySet()) {
@ -74,7 +75,7 @@ public class RestTestExecutionContext implements Closeable {
String body = actualBody(bodies);
try {
response = callApiInternal(apiName, requestParams, body);
response = callApiInternal(apiName, requestParams, body, headers);
//we always stash the last response body
stash.stashValue("body", response.getBody());
return response;
@ -104,8 +105,8 @@ public class RestTestExecutionContext implements Closeable {
return XContentFactory.jsonBuilder().map(body).string();
}
private RestResponse callApiInternal(String apiName, Map<String, String> params, String body) throws IOException, RestException {
return restClient.callApi(apiName, params, body);
private RestResponse callApiInternal(String apiName, Map<String, String> params, String body, Map<String, String> headers) throws IOException, RestException {
return restClient.callApi(apiName, params, body, headers);
}
/**

View File

@ -132,7 +132,7 @@ public class RestClient implements Closeable {
* @throws RestException if the obtained status code is non ok, unless the specific error code needs to be ignored
* according to the ignore parameter received as input (which won't get sent to elasticsearch)
*/
public RestResponse callApi(String apiName, Map<String, String> params, String body) throws IOException, RestException {
public RestResponse callApi(String apiName, Map<String, String> params, String body, Map<String, String> headers) throws IOException, RestException {
List<Integer> ignores = new ArrayList<>();
Map<String, String> requestParams = null;
@ -151,6 +151,9 @@ public class RestClient implements Closeable {
}
HttpRequestBuilder httpRequestBuilder = callApiBuilder(apiName, requestParams, body);
for (Map.Entry<String, String> header : headers.entrySet()) {
httpRequestBuilder.addHeader(header.getKey(), header.getValue());
}
logger.debug("calling api [{}]", apiName);
HttpResponse httpResponse = httpRequestBuilder.execute();

View File

@ -25,6 +25,8 @@ import org.elasticsearch.test.rest.section.ApiCallSection;
import org.elasticsearch.test.rest.section.DoSection;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Parser for do sections
@ -40,6 +42,8 @@ public class DoSectionParser implements RestTestFragmentParser<DoSection> {
XContentParser.Token token;
DoSection doSection = new DoSection();
ApiCallSection apiCallSection = null;
Map<String, String> headers = new HashMap<>();
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
@ -49,8 +53,17 @@ public class DoSectionParser implements RestTestFragmentParser<DoSection> {
doSection.setCatch(parser.text());
}
} else if (token == XContentParser.Token.START_OBJECT) {
if (currentFieldName != null) {
ApiCallSection apiCallSection = new ApiCallSection(currentFieldName);
if ("headers".equals(currentFieldName)) {
String headerName = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
headerName = parser.currentName();
} else if (token.isValue()) {
headers.put(headerName, parser.text());
}
}
} else if (currentFieldName != null) { // must be part of API call then
apiCallSection = new ApiCallSection(currentFieldName);
String paramName = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
@ -73,17 +86,20 @@ public class DoSectionParser implements RestTestFragmentParser<DoSection> {
}
}
}
doSection.setApiCallSection(apiCallSection);
}
}
}
parser.nextToken();
if (doSection.getApiCallSection() == null) {
throw new RestTestParseException("client call section is mandatory within a do section");
try {
if (apiCallSection == null) {
throw new RestTestParseException("client call section is mandatory within a do section");
}
if (headers.isEmpty() == false) {
apiCallSection.addHeaders(headers);
}
doSection.setApiCallSection(apiCallSection);
} finally {
parser.nextToken();
}
return doSection;
}
}

View File

@ -33,6 +33,7 @@ public class ApiCallSection {
private final String api;
private final Map<String, String> params = new HashMap<>();
private final Map<String, String> headers = new HashMap<>();
private final List<Map<String, Object>> bodies = new ArrayList<>();
public ApiCallSection(String api) {
@ -56,6 +57,18 @@ public class ApiCallSection {
this.params.put(key, value);
}
public void addHeaders(Map<String, String> otherHeaders) {
this.headers.putAll(otherHeaders);
}
public void addHeader(String key, String value) {
this.headers.put(key, value);
}
public Map<String, String> getHeaders() {
return unmodifiableMap(headers);
}
public List<Map<String, Object>> getBodies() {
return Collections.unmodifiableList(bodies);
}

View File

@ -45,6 +45,9 @@ import static org.junit.Assert.fail;
*
* - do:
* catch: missing
* headers:
* Authorization: Basic user:pass
* Content-Type: application/json
* update:
* index: test_1
* type: test
@ -86,7 +89,8 @@ public class DoSection implements ExecutableSection {
}
try {
RestResponse restResponse = executionContext.callApi(apiCallSection.getApi(), apiCallSection.getParams(), apiCallSection.getBodies());
RestResponse restResponse = executionContext.callApi(apiCallSection.getApi(), apiCallSection.getParams(),
apiCallSection.getBodies(), apiCallSection.getHeaders());
if (Strings.hasLength(catchParam)) {
String catchStatusCode;
if (catches.containsKey(catchParam)) {

View File

@ -34,7 +34,7 @@ import java.util.List;
*/
public final class Features {
private static final List<String> SUPPORTED = Arrays.asList("stash_in_path", "groovy_scripting");
private static final List<String> SUPPORTED = Arrays.asList("stash_in_path", "groovy_scripting", "headers");
private Features() {

View File

@ -341,6 +341,29 @@ public class DoSectionParserTests extends AbstractParserTestCase {
assertThat(doSection.getApiCallSection().hasBody(), equalTo(false));
}
public void testParseDoSectionWithHeaders() throws Exception {
parser = YamlXContent.yamlXContent.createParser(
"headers:\n" +
" Authorization: \"thing one\"\n" +
" Content-Type: \"application/json\"\n" +
"indices.get_warmer:\n" +
" index: test_index\n" +
" name: test_warmer"
);
DoSectionParser doSectionParser = new DoSectionParser();
DoSection doSection = doSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser));
assertThat(doSection.getApiCallSection(), notNullValue());
assertThat(doSection.getApiCallSection().getApi(), equalTo("indices.get_warmer"));
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(2));
assertThat(doSection.getApiCallSection().hasBody(), equalTo(false));
assertThat(doSection.getApiCallSection().getHeaders(), notNullValue());
assertThat(doSection.getApiCallSection().getHeaders().size(), equalTo(2));
assertThat(doSection.getApiCallSection().getHeaders().get("Authorization"), equalTo("thing one"));
assertThat(doSection.getApiCallSection().getHeaders().get("Content-Type"), equalTo("application/json"));
}
public void testParseDoSectionWithoutClientCallSection() throws Exception {
parser = YamlXContent.yamlXContent.createParser(
"catch: missing\n"