package org.httpkit.server; import clojure.lang.IPersistentMap; import clojure.lang.PersistentArrayMap; import org.httpkit.LineTooLargeException; import org.httpkit.ProtocolException; import org.httpkit.RequestTooLargeException; import org.httpkit.server.MockClojureHandler; import org.junit.Assert; import org.junit.Test; import java.nio.ByteBuffer; import java.util.Map; import java.util.TreeMap; import java.util.Vector; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; public class RingHandlerTest { private HttpDecoder httpDecoder = new HttpDecoder(8388608, 4096, ProxyProtocolOption.DISABLED); @Test public void shouldUseExternalThreadPoolForExecution() throws InterruptedException, ProtocolException, LineTooLargeException, RequestTooLargeException { Vector<String> assertionItems = new Vector<String>(); ExecutorService testWorkerPool = new ThreadPoolExecutor(1, 1, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue(2)); RingHandler ringHandler = new RingHandler(new MockClojureHandler(aDummyResponse()), testWorkerPool); ringHandler.handle(aDummyRequest(), new MockRespCallback(assertionItems)); Thread.sleep(50); assertDummyRequestReceived(assertionItems); } @Test public void shouldUseInternalThreadPoolForExecution() throws InterruptedException, ProtocolException, LineTooLargeException, RequestTooLargeException { Vector<String> assertionItems = new Vector<String>(); RingHandler ringHandler = new RingHandler(1, new MockClojureHandler(aDummyResponse()), "some-prefix", 2); ringHandler.handle(aDummyRequest(), new MockRespCallback(assertionItems)); Thread.sleep(50); assertDummyRequestReceived(assertionItems); } public class MockRespCallback extends RespCallback { private Vector<String> storage; public MockRespCallback(Vector<String> storage) { super(null, null); this.storage = storage; } @Override public void run(ByteBuffer... buffers) { StringBuilder builder = new StringBuilder(); for (ByteBuffer buffer : buffers) { builder.append(new String(buffer.array())); } storage.add(builder.toString()); } } private HttpRequest asHttpRequest(String... requestLines) throws ProtocolException, LineTooLargeException, RequestTooLargeException { httpDecoder.reset(); String joinedRequest = String.join("\n", requestLines); return httpDecoder.decode(ByteBuffer.wrap((joinedRequest + "\n\n").getBytes())); } private IPersistentMap aDummyResponse() { Map<Object, Object> m = new TreeMap<Object, Object>(); m.put(ClojureRing.BODY, "DUMMY_RESPONSE"); m.put(ClojureRing.STATUS, 301); return PersistentArrayMap.create(m); } private HttpRequest aDummyRequest() throws ProtocolException, LineTooLargeException, RequestTooLargeException { return asHttpRequest( "GET /foo/bar?query=baz HTTP/1.0", "Host: github.com/http-kit/http-kit", "Content-Type: text/html", "x-forwarded-for: 0.0.0.0:80"); } private void assertDummyRequestReceived(Vector<String> assertionItems) { Assert.assertThat("should return only one single response", assertionItems.size(), is(1)); String element = assertionItems.firstElement(); Assert.assertThat("should write dummy-response as a side-effect", element, containsString("DUMMY_RESPONSE")); Assert.assertThat("should write dummy-response with correct status code", element, containsString("HTTP/1.1 301 Moved Permanently")); } }