/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.test.http; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import org.apache.commons.io.IOUtils; import org.geoserver.ows.util.KvpUtils; import org.geotools.data.ows.HTTPResponse; /** * A simple mock http client, allows to set expectations on requests and provide canned responses on * them * * @author Andrea Aime - GeoSolutions * */ public class MockHttpClient extends AbstractHttpClient { Map<Request, HTTPResponse> expectedRequests = new LinkedHashMap<MockHttpClient.Request, HTTPResponse>(); /** * Binds a certain URL to a response. The order of the query string parameters is not relevant, * the code will match the same set of KVP params regardless of their sequence and case of their * keys (from OGC specs, keys are case insensitive, values are case sensitive) * * @param url * @param response */ public void expectGet(URL url, HTTPResponse response) { expectedRequests.put(new Request(url), response); } /** * Binds a certain POST request to a response. * * @param url * @param response */ public void expectPost(URL url, String postContent, String postContentType, HTTPResponse response) { expectPOST(url, postContent.getBytes(), postContentType, response); } public void expectPOST(URL url, byte[] postContent, String postContentType, HTTPResponse response) { expectedRequests.put(new Request(url, postContent, postContentType), response); } @Override public HTTPResponse post(URL url, InputStream postContent, String postContentType) throws IOException { return getResponse(new Request(url, toByteArray(postContent), postContentType)); } private byte[] toByteArray(InputStream is) throws IOException { try { return IOUtils.toByteArray(is); } finally { is.close(); } } private HTTPResponse getResponse(Request request) { HTTPResponse response = expectedRequests.get(request); if (response == null) { StringBuilder sb = new StringBuilder("Unexpected request \n" + request + "\nNo response is bound to it. Bound urls are: "); for (Request r : expectedRequests.keySet()) { sb.append("\n").append(r); } throw new IllegalArgumentException(sb.toString()); } return response; } @Override public HTTPResponse get(URL url) throws IOException { return getResponse(new Request(url)); } private static class Request { String path; Map<String, Object> kvp; String contentType; boolean isGetRequest; byte[] postContent; public Request(URL url) { this.path = url.getProtocol() + "://" + url.getHost() + url.getPath(); Map<String, Object> parsedQueryString = KvpUtils.parseQueryString(url.toExternalForm()); // we use a treemap as it makes it easier to see what's missing when no bound url is found this.kvp = new TreeMap<String, Object>(); for (Entry<String, Object> entry : parsedQueryString.entrySet()) { this.kvp.put(entry.getKey().toUpperCase(), entry.getValue()); } this.isGetRequest = true; } public Request(URL url, byte[] postContent, String postContentType) { this(url); this.isGetRequest = false; this.postContent = postContent; this.contentType = postContentType; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((contentType == null) ? 0 : contentType.hashCode()); result = prime * result + (isGetRequest ? 1231 : 1237); result = prime * result + ((kvp == null) ? 0 : kvp.hashCode()); result = prime * result + ((path == null) ? 0 : path.hashCode()); result = prime * result + Arrays.hashCode(postContent); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Request other = (Request) obj; if (contentType == null) { if (other.contentType != null) return false; } else if (!contentType.equals(other.contentType)) return false; if (isGetRequest != other.isGetRequest) return false; if (kvp == null) { if (other.kvp != null) return false; } else if (!kvp.equals(other.kvp)) return false; if (path == null) { if (other.path != null) return false; } else if (!path.equals(other.path)) return false; if (!Arrays.equals(postContent, other.postContent)) return false; return true; } @Override public String toString() { if (isGetRequest) { return "GET " + path + ", " + kvp; } else { return "POST " + path + ", " + kvp + ", content type " + contentType + ", content " + Arrays.toString(postContent); } } } }