/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.elasticsearch.test.rest.yaml; import org.apache.http.Header; import org.apache.http.client.methods.HttpHead; import org.apache.http.util.EntityUtils; import org.elasticsearch.client.Response; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; /** * Response obtained from a REST call, eagerly reads the response body into a string for later optional parsing. * Supports parsing the response body when needed and returning specific values extracted from it. */ public class ClientYamlTestResponse { private final Response response; private final byte[] body; private final XContentType bodyContentType; private ObjectPath parsedResponse; private String bodyAsString; ClientYamlTestResponse(Response response) throws IOException { this.response = response; if (response.getEntity() != null) { String contentType = response.getHeader("Content-Type"); this.bodyContentType = XContentType.fromMediaTypeOrFormat(contentType); try { byte[] bytes = EntityUtils.toByteArray(response.getEntity()); //skip parsing if we got text back (e.g. if we called _cat apis) if (bodyContentType != null) { this.parsedResponse = ObjectPath.createFromXContent(bodyContentType.xContent(), new BytesArray(bytes)); } this.body = bytes; } catch (IOException e) { EntityUtils.consumeQuietly(response.getEntity()); throw e; } } else { this.body = null; this.bodyContentType = null; } } public int getStatusCode() { return response.getStatusLine().getStatusCode(); } public String getReasonPhrase() { return response.getStatusLine().getReasonPhrase(); } /** * Get a list of all of the values of all warning headers returned in the response. */ public List<String> getWarningHeaders() { List<String> warningHeaders = new ArrayList<>(); for (Header header : response.getHeaders()) { if (header.getName().equals("Warning")) { warningHeaders.add(header.getValue()); } } return warningHeaders; } /** * Returns the body properly parsed depending on the content type. * Might be a string or a json object parsed as a map. */ public Object getBody() throws IOException { if (parsedResponse != null) { return parsedResponse.evaluate(""); } //we only get here if there is no response body or the body is text assert bodyContentType == null; return getBodyAsString(); } /** * Returns the body as a string */ public String getBodyAsString() { if (bodyAsString == null && body != null) { //content-type null means that text was returned if (bodyContentType == null || bodyContentType == XContentType.JSON || bodyContentType == XContentType.YAML) { bodyAsString = new String(body, StandardCharsets.UTF_8); } else { //if the body is in a binary format and gets requested as a string (e.g. to log a test failure), we convert it to json try (XContentBuilder jsonBuilder = XContentFactory.jsonBuilder()) { try (XContentParser parser = bodyContentType.xContent().createParser(NamedXContentRegistry.EMPTY, body)) { jsonBuilder.copyCurrentStructure(parser); } bodyAsString = jsonBuilder.string(); } catch (IOException e) { throw new UncheckedIOException("unable to convert response body to a string format", e); } } } return bodyAsString; } public boolean isError() { return response.getStatusLine().getStatusCode() >= 400; } /** * Parses the response body and extracts a specific value from it (identified by the provided path) */ public Object evaluate(String path) throws IOException { return evaluate(path, Stash.EMPTY); } /** * Parses the response body and extracts a specific value from it (identified by the provided path) */ public Object evaluate(String path, Stash stash) throws IOException { if (response == null) { return null; } if (parsedResponse == null) { //special case: api that don't support body (e.g. exists) return true if 200, false if 404, even if no body //is_true: '' means the response had no body but the client returned true (caused by 200) //is_false: '' means the response had no body but the client returned false (caused by 404) if ("".equals(path) && HttpHead.METHOD_NAME.equals(response.getRequestLine().getMethod())) { return isError() == false; } return null; } return parsedResponse.evaluate(path, stash); } }