blob: a8baca36401375ed5c8c3be51c1bf87127f1ee04 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* 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.apache.sling.testing.clients;
import org.apache.http.*;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.util.*;
import java.util.regex.Pattern;
public class SlingHttpResponse implements CloseableHttpResponse {
public static final String STATUS = "Status";
public static final String MESSAGE = "Message";
public static final String LOCATION = "Location";
public static final String PARENT_LOCATION = "ParentLocation";
public static final String PATH = "Path";
public static final String REFERER = "Referer";
public static final String CHANGE_LOG = "ChangeLog";
private final CloseableHttpResponse httpResponse;
private String content;
public SlingHttpResponse(CloseableHttpResponse response) {
this.httpResponse = response;
}
/**
* <p>Get the {@code String} content of the response.</p>
* <p>The content is cached so it is safe to call this method several times.</p>
* <p><b>Attention!</b> Calling this method consumes the entity, so it cannot be used as an InputStream later</p>
*
* @return the content as String
*/
public String getContent() {
if (!this.isConsumed()) {
try {
this.content = EntityUtils.toString(this.getEntity());
this.close();
} catch (IOException e) {
throw new RuntimeException("Could not read content from response", e);
}
}
return content;
}
public boolean isConsumed() {
return this.content != null || this.getEntity() == null;
}
/**
* <p>Assert that response matches supplied status</p>
*
* @param expected the expected http status
* @throws ClientException if the response does not match the expected
*/
public void checkStatus(int expected) throws ClientException {
if (this.getStatusLine().getStatusCode() != expected) {
throw new ClientException(this + " has wrong response status ("
+ this.getStatusLine().getStatusCode() + "). Expected " + expected);
}
}
/**
* <p>Assert that response matches supplied content type (from Content-Type header)</p>
*
* @param expected the expected content type
* @throws ClientException if the response content type does not match the expected
*/
public void checkContentType(String expected) throws ClientException {
// Remove whatever follows semicolon in content-type
String contentType = this.getEntity().getContentType().getValue();
if (contentType != null) {
contentType = contentType.split(";")[0].trim();
}
// check for match
if (!contentType.equals(expected)) {
throw new ClientException(this + " has wrong content type (" + contentType + "). Expected " + expected);
}
}
/**
* <p>For each regular expression, assert that at least one line of the response matches the expression</p>
* <p>The regular expressions are automatically prefixed and suffixed with .* it order to partial-match the lines</p>
*
* @param regexp list of regular expressions
* @throws ClientException if the response content does not match one of the regexp
*/
public void checkContentRegexp(String... regexp) throws ClientException {
for(String expr : regexp) {
final Pattern p = Pattern.compile(".*" + expr + ".*");
final Scanner scanner = new Scanner(this.getContent());
boolean matched = false;
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (p.matcher(line).matches()) {
matched = true;
break;
}
}
if (!matched) {
throw new ClientException("Pattern " + p + " didn't match any line in content");
}
}
}
/**
* <p>Assert that all the provided {@code Strings} are contained in the response</p>
*
* @param expected list of expected strings
* @throws ClientException @throws ClientException if the response content does not match one of the strings
*/
public void checkContentContains(String... expected) throws ClientException {
for (String s : expected) {
if (!this.getContent().contains(s)) {
throw new ClientException("Content does not contain string " + s + ". Content is: \n\n" + getContent());
}
}
}
/**
* Get status from Sling Response
*
* @return Sling Status
*/
public String getSlingStatus() {
String searchPattern = "id=\"" + STATUS + "\">";
return extractFromHTMLResponse(searchPattern);
}
/**
* Get status from Sling Response as integer
*
* @return Sling Status
* @throws NumberFormatException if sling status can't be parsed as a number
*/
public int getSlingStatusAsInt() throws NumberFormatException {
String strStatus = getSlingStatus();
return Integer.parseInt(strStatus);
}
/**
* Get message from Sling Response
*
* @return Sling Message
*/
public String getSlingMessage() {
String searchPattern = "id=\"" + MESSAGE + "\">";
return extractFromHTMLResponse(searchPattern);
}
/**
* Get copy paths from message
*
* @return copy paths as String Array
*/
public String[] getSlingCopyPaths() {
String copyPaths = getSlingMessage();
StringTokenizer tokenizer = new StringTokenizer(copyPaths);
List<String> copies = new ArrayList<String>();
while (tokenizer.hasMoreElements()) {
copies.add(tokenizer.nextToken());
}
return copies.toArray(new String[copies.size()]);
}
/**
* Get location from Sling Response
*
* @return Sling Location
*/
public String getSlingLocation() {
String searchPattern = "id=\"" + LOCATION + "\">";
return extractFromHTMLResponse(searchPattern);
}
/**
* Get parent location from Sling Response
*
* @return Sling Parent Location
*/
public String getSlingParentLocation() {
String searchPattern = "id=\"" + PARENT_LOCATION + "\">";
return extractFromHTMLResponse(searchPattern);
}
/**
* Get path from Sling Response
*
* @return Sling Path
*/
public String getSlingPath() {
String searchPattern = "id=\"" + PATH + "\">";
return extractFromHTMLResponse(searchPattern);
}
/**
* Get referer from Sling Response
*
* @return Sling Referer
*/
public String getSlingReferer() {
String searchPattern = "id=\"" + REFERER + "\">";
return extractFromHTMLResponse(searchPattern);
}
/**
* Get change log from Sling Response
*
* @return Sling Change Log
*/
public String getSlingChangeLog() {
String searchPattern = "id=\"" + CHANGE_LOG + "\">";
return extractFromHTMLResponse(searchPattern);
}
/**
* Extract information from response
*
* @param searchPattern search pattern to look for
* @return Sling information
*/
protected String extractFromHTMLResponse(String searchPattern) {
String tmpResponse = null;
int start = getContent().indexOf(searchPattern);
if (start > 0) {
start += searchPattern.length();
tmpResponse = getContent().substring(start);
int end = tmpResponse.indexOf("<");
tmpResponse = tmpResponse.substring(0, end);
}
return tmpResponse;
}
// HttpResponse delegated methods
@Override
public StatusLine getStatusLine() {
return httpResponse.getStatusLine();
}
@Override
public void setStatusLine(StatusLine statusline) {
httpResponse.setStatusLine(statusline);
}
@Override
public void setStatusLine(ProtocolVersion ver, int code) {
httpResponse.setStatusLine(ver, code);
}
@Override
public void setStatusLine(ProtocolVersion ver, int code, String reason) {
httpResponse.setStatusLine(ver, code, reason);
}
@Override
public void setStatusCode(int code) throws IllegalStateException {
httpResponse.setStatusCode(code);
}
@Override
public void setReasonPhrase(String reason) throws IllegalStateException {
httpResponse.setReasonPhrase(reason);
}
@Override
public HttpEntity getEntity() {
return httpResponse.getEntity();
}
@Override
public void setEntity(HttpEntity entity) {
httpResponse.setEntity(entity);
}
@Override
public Locale getLocale() {
return httpResponse.getLocale();
}
@Override
public void setLocale(Locale loc) {
httpResponse.setLocale(loc);
}
@Override
public ProtocolVersion getProtocolVersion() {
return httpResponse.getProtocolVersion();
}
@Override
public boolean containsHeader(String name) {
return httpResponse.containsHeader(name);
}
@Override
public Header[] getHeaders(String name) {
return httpResponse.getHeaders(name);
}
@Override
public Header getFirstHeader(String name) {
return httpResponse.getFirstHeader(name);
}
@Override
public Header getLastHeader(String name) {
return httpResponse.getLastHeader(name);
}
@Override
public Header[] getAllHeaders() {
return httpResponse.getAllHeaders();
}
@Override
public void addHeader(Header header) {
httpResponse.addHeader(header);
}
@Override
public void addHeader(String name, String value) {
httpResponse.addHeader(name, value);
}
@Override
public void setHeader(Header header) {
httpResponse.setHeader(header);
}
@Override
public void setHeader(String name, String value) {
httpResponse.setHeader(name, value);
}
@Override
public void setHeaders(Header[] headers) {
httpResponse.setHeaders(headers);
}
@Override
public void removeHeader(Header header) {
httpResponse.removeHeader(header);
}
@Override
public void removeHeaders(String name) {
httpResponse.removeHeaders(name);
}
@Override
public HeaderIterator headerIterator() {
return httpResponse.headerIterator();
}
@Override
public HeaderIterator headerIterator(String name) {
return httpResponse.headerIterator(name);
}
@SuppressWarnings("deprecation")
@Override
public HttpParams getParams() {
return httpResponse.getParams();
}
@SuppressWarnings("deprecation")
@Override
public void setParams(HttpParams params) {
httpResponse.setParams(params);
}
@Override
public void close() throws IOException {
httpResponse.close();
}
}