Java tutorial
/* * Copyright 2013 TORCH UG * * This file is part of Graylog2. * * Graylog2 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Graylog2 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Graylog2. If not, see <http://www.gnu.org/licenses/>. */ package lib; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseBodyPart; import com.ning.http.client.HttpResponseHeaders; import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.ListenableFuture; import com.ning.http.client.Request; import com.ning.http.client.Response; import com.ning.http.client.cookie.Cookie; import com.ning.http.client.listenable.AbstractListenableFuture; import play.mvc.Http; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class StubHttpProvider implements AsyncHttpProvider { private Map<URL, Expectation> expectations = Maps.newHashMap(); private Set<Expectation> fulfilledExpectations = Sets.newHashSet(); public StubHttpProvider expectResponse(URL url, int statusCode, String payload) { expectations.put(url, new Expectation(url, statusCode, payload)); return this; } /** * Can be used to re-use the same StubHttpProvider in test cases, but it's cheap enough to tearDown/setUp a new instance */ public void reset() { fulfilledExpectations.clear(); expectations.clear(); } public boolean isExpectationsFulfilled() { return unfulfilledExpectations().isEmpty(); } public Set<Expectation> unfulfilledExpectations() { return Sets.difference(Sets.newHashSet(expectations.values()), fulfilledExpectations); } @Override public <T> ListenableFuture<T> execute(Request request, AsyncHandler<T> handler) throws IOException { final Expectation expectation = expectations.get(new URL(request.getUrl())); if (expectation == null) { throw new RuntimeException("Unknown URL requested, failing test: " + request.getUrl()); } fulfilledExpectations.add(expectation); T t = null; try { final URI uri = expectation.getUrl().toURI(); handler.onStatusReceived(new HttpResponseStatus(uri, this) { @Override public int getStatusCode() { return expectation.getStatusCode(); } @Override public String getStatusText() { return ""; // TODO } @Override public String getProtocolName() { return expectation.getUrl().getProtocol(); } @Override public int getProtocolMajorVersion() { return 1; } @Override public int getProtocolMinorVersion() { return 1; } @Override public String getProtocolText() { return ""; // TODO } }); handler.onHeadersReceived(new HttpResponseHeaders(uri, this) { @Override public FluentCaseInsensitiveStringsMap getHeaders() { return new FluentCaseInsensitiveStringsMap(); } }); handler.onBodyPartReceived(new HttpResponseBodyPart(uri, this) { @Override public byte[] getBodyPartBytes() { return expectation.getPayload().getBytes(Charset.forName("UTF-8")); } @Override public int writeTo(OutputStream outputStream) throws IOException { final byte[] bodyPartBytes = getBodyPartBytes(); outputStream.write(bodyPartBytes); return bodyPartBytes.length; } @Override public ByteBuffer getBodyByteBuffer() { return ByteBuffer.wrap(getBodyPartBytes()); } @Override public boolean isLast() { return true; } @Override public void markUnderlyingConnectionAsClosed() { } @Override public boolean closeUnderlyingConnection() { return true; } @Override public int length() { return getBodyPartBytes().length; } }); t = handler.onCompleted(); } catch (Exception e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } final T finalT = t; final Future<T> futureT = Executors.newSingleThreadExecutor().submit(new Callable<T>() { @Override public T call() throws Exception { return finalT; } }); return new ImmediateFuture<>(futureT); } @Override public void close() { } @Override public Response prepareResponse(final HttpResponseStatus status, final HttpResponseHeaders headers, final List<HttpResponseBodyPart> bodyParts) { final HttpResponseBodyPart bodyPart = bodyParts.get(0); return new Response() { @Override public int getStatusCode() { return status.getStatusCode(); } @Override public String getStatusText() { return status.getStatusText(); } @Override public byte[] getResponseBodyAsBytes() throws IOException { return bodyPart.getBodyPartBytes(); } @Override public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { return bodyPart.getBodyByteBuffer(); } @Override public InputStream getResponseBodyAsStream() throws IOException { return null; // TODO } @Override public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException { return ""; // TODO } @Override public String getResponseBody(String charset) throws IOException { return new String(bodyPart.getBodyPartBytes(), charset); } @Override public String getResponseBodyExcerpt(int maxLength) throws IOException { return null; // TODO } @Override public String getResponseBody() throws IOException { return new String(bodyPart.getBodyPartBytes()); } @Override public URI getUri() throws MalformedURLException { return status.getUrl(); } @Override public String getContentType() { return Http.MimeTypes.JSON; } @Override public String getHeader(String name) { return headers.getHeaders().get(name).get(0); } @Override public List<String> getHeaders(String name) { return headers.getHeaders().get(name); } @Override public FluentCaseInsensitiveStringsMap getHeaders() { return headers.getHeaders(); } @Override public boolean isRedirected() { return false; } @Override public List<Cookie> getCookies() { return null; } @Override public boolean hasResponseStatus() { return false; } @Override public boolean hasResponseHeaders() { return false; } @Override public boolean hasResponseBody() { return false; } }; } private class Expectation { private final URL url; private final int statusCode; private final String payload; public Expectation(URL url, int statusCode, String payload) { this.url = url; this.statusCode = statusCode; this.payload = payload; } private URL getUrl() { return url; } private int getStatusCode() { return statusCode; } private String getPayload() { return payload; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Expectation that = (Expectation) o; if (statusCode != that.statusCode) return false; if (!payload.equals(that.payload)) return false; if (!url.equals(that.url)) return false; return true; } @Override public int hashCode() { int result = url.hashCode(); result = 31 * result + statusCode; result = 31 * result + payload.hashCode(); return result; } } private class ImmediateFuture<V> extends AbstractListenableFuture<V> { private final Future<V> response; public ImmediateFuture(Future<V> response) { this.response = response; } @Override public void done() { } @Override public void abort(Throwable t) { } @Override public void content(V v) { } @Override public void touch() { } @Override public boolean getAndSetWriteHeaders(boolean writeHeader) { return false; } @Override public boolean getAndSetWriteBody(boolean writeBody) { return false; } @Override public boolean cancel(boolean mayInterruptIfRunning) { return false; } @Override public boolean isCancelled() { return false; } @Override public boolean isDone() { return true; } @Override public V get() throws InterruptedException, ExecutionException { return response.get(); } @Override public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return response.get(timeout, unit); } } }