| 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(); |
| } |
| } |
| } |