blob: 208d41cb86bf2f34d3a8add4817e0f8d314a064a [file] [log] [blame]
package com.xtremelabs.robolectric.tester.org.apache.http;
import com.xtremelabs.robolectric.Robolectric;
import org.apache.http.*;
import org.apache.http.client.RequestDirector;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
import javax.xml.ws.http.HTTPException;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
public class FakeHttpLayer {
List<HttpResponse> pendingHttpResponses = new ArrayList<HttpResponse>();
List<HttpRequestInfo> httpRequestInfos = new ArrayList<HttpRequestInfo>();
List<HttpEntityStub.ResponseRule> httpResponseRules = new ArrayList<HttpEntityStub.ResponseRule>();
HttpResponse defaultHttpResponse;
private HttpResponse defaultResponse;
public HttpRequestInfo getLastSentHttpRequestInfo() {
List<HttpRequestInfo> requestInfos = Robolectric.getFakeHttpLayer().getSentHttpRequestInfos();
if (requestInfos.isEmpty()) {
return null;
}
return requestInfos.get(requestInfos.size() - 1);
}
public void addPendingHttpResponse(int statusCode, String responseBody) {
addPendingHttpResponse(new TestHttpResponse(statusCode, responseBody));
}
public void addPendingHttpResponseWithContentType(int statusCode, String responseBody, Header contentType) {
addPendingHttpResponse(new TestHttpResponse(statusCode, responseBody, new Header[] {contentType}));
}
public void addPendingHttpResponse(HttpResponse httpResponse) {
pendingHttpResponses.add(httpResponse);
}
public void addHttpResponseRule(String method, String uri, HttpResponse response) {
addHttpResponseRule(new DefaultRequestMatcher(method, uri), response);
}
public void addHttpResponseRule(String uri, HttpResponse response) {
addHttpResponseRule(new UriRequestMatcher(uri), response);
}
public void addHttpResponseRule(String uri, String response) {
addHttpResponseRule(new UriRequestMatcher(uri), new TestHttpResponse(200, response));
}
public void addHttpResponseRule(RequestMatcher requestMatcher, HttpResponse response) {
addHttpResponseRule(new RequestMatcherResponseRule(requestMatcher, response));
}
/**
* Add a response rule.
* @param requestMatcher Request matcher
* @param responses A list of responses that are returned to matching requests in order from first to last.
*/
public void addHttpResponseRule(RequestMatcher requestMatcher, List<? extends HttpResponse> responses) {
addHttpResponseRule(new RequestMatcherResponseRule(requestMatcher, responses));
}
public void addHttpResponseRule(HttpEntityStub.ResponseRule responseRule) {
httpResponseRules.add(responseRule);
}
public void setDefaultHttpResponse(HttpResponse defaultHttpResponse) {
this.defaultHttpResponse = defaultHttpResponse;
}
public void setDefaultHttpResponse(int statusCode, String responseBody) {
setDefaultHttpResponse(new TestHttpResponse(statusCode, responseBody));
}
private HttpResponse findResponse(HttpRequest httpRequest) throws HttpException, IOException {
if (!pendingHttpResponses.isEmpty()) {
return pendingHttpResponses.remove(0);
}
for (HttpEntityStub.ResponseRule httpResponseRule : httpResponseRules) {
if (httpResponseRule.matches(httpRequest)) {
return httpResponseRule.getResponse();
}
}
return defaultHttpResponse;
}
public HttpResponse emulateRequest(HttpHost httpHost, HttpRequest httpRequest, HttpContext httpContext, RequestDirector requestDirector) throws HttpException, IOException {
HttpResponse httpResponse = findResponse(httpRequest);
if (httpResponse == null) {
throw new RuntimeException("Unexpected call to execute, no pending responses are available. See Robolectric.addPendingResponse(). Request was: " +
httpRequest.getRequestLine().getMethod() + " " + httpRequest.getRequestLine().getUri());
} else {
HttpParams params = httpResponse.getParams();
if (HttpConnectionParams.getConnectionTimeout(params) < 0) {
throw new ConnectTimeoutException("Socket is not connected");
} else if (HttpConnectionParams.getSoTimeout(params) < 0) {
throw new ConnectTimeoutException("The operation timed out");
}
}
httpRequestInfos.add(new HttpRequestInfo(httpRequest, httpHost, httpContext, requestDirector));
return httpResponse;
}
public boolean hasPendingResponses() {
return !pendingHttpResponses.isEmpty();
}
public boolean hasRequestInfos() {
return !httpRequestInfos.isEmpty();
}
public void clearRequestInfos() {
httpRequestInfos.clear();
}
public boolean hasResponseRules() {
return !httpResponseRules.isEmpty();
}
public boolean hasRequestMatchingRule(RequestMatcher rule) {
for (HttpRequestInfo requestInfo : httpRequestInfos) {
if (rule.matches(requestInfo.httpRequest)) {
return true;
}
}
return false;
}
public HttpResponse getDefaultResponse() {
return defaultResponse;
}
public HttpRequestInfo getSentHttpRequestInfo(int index) {
return httpRequestInfos.get(index);
}
public List<HttpRequestInfo> getSentHttpRequestInfos() {
return new ArrayList<HttpRequestInfo>(httpRequestInfos);
}
public void clearHttpResponseRules() {
httpResponseRules.clear();
}
public void clearPendingHttpResponses() {
pendingHttpResponses.clear();
}
public static class RequestMatcherResponseRule implements HttpEntityStub.ResponseRule {
private RequestMatcher requestMatcher;
private HttpResponse responseToGive;
private IOException ioException;
private HTTPException httpException;
private List<? extends HttpResponse> responses;
public RequestMatcherResponseRule(RequestMatcher requestMatcher, HttpResponse responseToGive) {
this.requestMatcher = requestMatcher;
this.responseToGive = responseToGive;
}
public RequestMatcherResponseRule(RequestMatcher requestMatcher, IOException ioException) {
this.requestMatcher = requestMatcher;
this.ioException = ioException;
}
public RequestMatcherResponseRule(RequestMatcher requestMatcher, HTTPException httpException) {
this.requestMatcher = requestMatcher;
this.httpException = httpException;
}
public RequestMatcherResponseRule(RequestMatcher requestMatcher, List<? extends HttpResponse> responses) {
this.requestMatcher = requestMatcher;
this.responses = responses;
}
@Override public boolean matches(HttpRequest request) {
return requestMatcher.matches(request);
}
@Override public HttpResponse getResponse() throws HttpException, IOException {
if (httpException != null) throw httpException;
if (ioException != null) throw ioException;
if (responseToGive != null) {
return responseToGive;
}
else {
if (responses.isEmpty()) {
throw new RuntimeException("No more responses left to give");
}
return responses.remove(0);
}
}
}
public static class DefaultRequestMatcher implements RequestMatcher {
private String method;
private String uri;
public DefaultRequestMatcher(String method, String uri) {
this.method = method;
this.uri = uri;
}
@Override public boolean matches(HttpRequest request) {
return request.getRequestLine().getMethod().equals(method) &&
request.getRequestLine().getUri().equals(uri);
}
}
public static class UriRequestMatcher implements RequestMatcher {
private String uri;
public UriRequestMatcher(String uri) {
this.uri = uri;
}
@Override public boolean matches(HttpRequest request) {
return request.getRequestLine().getUri().equals(uri);
}
}
public static class RequestMatcherBuilder implements RequestMatcher {
private String method;
private String hostname;
private String path;
private boolean noParams;
private Map<String, String> params = new HashMap<String, String>();
public RequestMatcherBuilder method(String method) {
this.method = method;
return this;
}
public RequestMatcherBuilder host(String hostname) {
this.hostname = hostname;
return this;
}
public RequestMatcherBuilder path(String path) {
if (path.startsWith("/")) {
throw new RuntimeException("Path should not start with '/'");
}
this.path = "/" + path;
return this;
}
public RequestMatcherBuilder param(String name, String value) {
params.put(name, value);
return this;
}
public RequestMatcherBuilder noParams() {
noParams = true;
return this;
}
@Override public boolean matches(HttpRequest request) {
URI uri = URI.create(request.getRequestLine().getUri());
if (method != null && !method.equals(request.getRequestLine().getMethod())) {
return false;
}
if (hostname != null && !hostname.equals(uri.getHost())) {
return false;
}
if (path != null && !path.equals(uri.getRawPath())) {
return false;
}
if (noParams && !uri.getRawQuery().equals(null)) {
return false;
}
if (params.size() > 0) {
Map<String, String> requestParams = ParamsParser.parseParams(request);
return requestParams.equals(params);
}
return true;
}
}
public static class UriRegexMatcher implements RequestMatcher {
private String method;
private final Pattern uriRegex;
public UriRegexMatcher(String method, String uriRegex) {
this.method = method;
this.uriRegex = Pattern.compile(uriRegex);
}
@Override public boolean matches(HttpRequest request) {
return request.getRequestLine().getMethod().equals(method) &&
uriRegex.matcher(request.getRequestLine().getUri()).matches();
}
}
}