diff options
Diffstat (limited to 'clustercontroller-utils/src/test/java/com')
10 files changed, 204 insertions, 588 deletions
diff --git a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/AsyncHttpClientWithBaseTest.java b/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/AsyncHttpClientWithBaseTest.java deleted file mode 100644 index 0175eab84c2..00000000000 --- a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/AsyncHttpClientWithBaseTest.java +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.clustercontroller.utils.communication.http; - -import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncOperation; -import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncOperationImpl; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.fail; - -public class AsyncHttpClientWithBaseTest { - - @Test - public void testOverride() { - class HttpClient implements AsyncHttpClient<HttpResult> { - HttpRequest lastRequest; - @Override - public AsyncOperation<HttpResult> execute(HttpRequest r) { - lastRequest = r; - return new AsyncOperationImpl<>("test"); - } - @Override - public void close() { - } - } - - HttpClient client = new HttpClient(); - AsyncHttpClientWithBase<HttpResult> base = new AsyncHttpClientWithBase<>(client); - // No override by default - HttpRequest r = new HttpRequest().setPath("/foo").setHost("bar").setPort(50); - base.execute(r); - assertEquals(client.lastRequest, r); - // Base request always set - base.setHttpRequestBase(null); - base.execute(r); - assertEquals(client.lastRequest, r); - // Set an override - base.setHttpRequestBase(new HttpRequest().setHttpOperation(HttpRequest.HttpOp.DELETE)); - base.execute(r); - assertNotSame(client.lastRequest, r); - assertEquals(HttpRequest.HttpOp.DELETE, client.lastRequest.getHttpOperation()); - - base.close(); - } - - @Test - public void testClientMustBeSet() { - try{ - new AsyncHttpClientWithBase<>(null); - fail(); - } catch (IllegalArgumentException e) { - } - } - -} diff --git a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/DummyAsyncHttpClient.java b/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/DummyAsyncHttpClient.java deleted file mode 100644 index 7070fb8570e..00000000000 --- a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/DummyAsyncHttpClient.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.clustercontroller.utils.communication.http; - -import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncOperation; -import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncOperationImpl; - -public class DummyAsyncHttpClient implements AsyncHttpClient<HttpResult> { - HttpResult result; - HttpRequest lastRequest; - - public DummyAsyncHttpClient(HttpResult result) { - this.result = result; - } - - @Override - public AsyncOperation<HttpResult> execute(HttpRequest r) { - lastRequest = r; - AsyncOperationImpl<HttpResult> op = new AsyncOperationImpl<>(r.toString()); - op.setResult(result); - return op; - } - - @Override - public void close() { - } -} diff --git a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/JsonAsyncHttpClientTest.java b/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/JsonAsyncHttpClientTest.java deleted file mode 100644 index 3d3cd517020..00000000000 --- a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/JsonAsyncHttpClientTest.java +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.clustercontroller.utils.communication.http; - -import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncOperation; -import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncOperationImpl; -import org.codehaus.jettison.json.JSONObject; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -public class JsonAsyncHttpClientTest { - - @Test - public void testJSONInJSONOut() throws Exception { - DummyAsyncHttpClient dummy = new DummyAsyncHttpClient( - new HttpResult().setContent(new JSONObject().put("bar", 42))); - JsonAsyncHttpClient client = new JsonAsyncHttpClient(dummy); - client.addJsonContentType(true); - client.verifyRequestContentAsJson(true); - - HttpRequest r = new HttpRequest(); - r.setPostContent(new JSONObject().put("foo", 34)); - - AsyncOperation<JsonHttpResult> result = client.execute(r); - - assertEquals(new JSONObject().put("bar", 42).toString(), result.getResult().getJson().toString()); - assertTrue(result.isSuccess()); - - result.toString(); - client.close(); - } - - @Test - public void testStringInJSONOut() throws Exception { - DummyAsyncHttpClient dummy = new DummyAsyncHttpClient( - new HttpResult().setContent(new JSONObject().put("bar", 42).toString())); - JsonAsyncHttpClient client = new JsonAsyncHttpClient(dummy); - - HttpRequest r = new HttpRequest(); - r.setPostContent(new JSONObject().put("foo", 34).toString()); - - AsyncOperation<JsonHttpResult> result = client.execute(r); - - assertEquals(new JSONObject().put("bar", 42).toString(), result.getResult().getJson().toString()); - } - - @Test - public void testIllegalJsonIn() throws Exception { - DummyAsyncHttpClient dummy = new DummyAsyncHttpClient( - new HttpResult().setContent(new JSONObject().put("bar", 42))); - JsonAsyncHttpClient client = new JsonAsyncHttpClient(dummy); - - try { - HttpRequest r = new HttpRequest(); - r.setPostContent("my illegal json"); - - client.execute(r); - assertTrue(false); - } catch (Exception e) { - - } - } - - @Test - public void testIllegalJSONOut() throws Exception { - DummyAsyncHttpClient dummy = new DummyAsyncHttpClient( - new HttpResult().setContent("my illegal json")); - JsonAsyncHttpClient client = new JsonAsyncHttpClient(dummy); - - HttpRequest r = new HttpRequest(); - r.setPostContent(new JSONObject().put("foo", 34).toString()); - - AsyncOperation<JsonHttpResult> result = client.execute(r); - - assertEquals("{\"error\":\"Invalid JSON in output: A JSONObject text must begin with '{' at character 1 of my illegal json\",\"output\":\"my illegal json\"}", result.getResult().getJson().toString()); - } - - @Test - public void testEmptyReply() { - class Client implements AsyncHttpClient<HttpResult> { - AsyncOperationImpl<HttpResult> lastOp; - @Override - public AsyncOperation<HttpResult> execute(HttpRequest r) { - return lastOp = new AsyncOperationImpl<>(r.toString()); - } - @Override - public void close() { - } - }; - Client client = new Client(); - JsonAsyncHttpClient jsonClient = new JsonAsyncHttpClient(client); - AsyncOperation<JsonHttpResult> op = jsonClient.execute(new HttpRequest()); - client.lastOp.setResult(null); - assertNull(op.getResult()); - } - - @Test - public void testNotVerifyingJson() throws Exception { - DummyAsyncHttpClient dummy = new DummyAsyncHttpClient( - new HttpResult().setContent(new JSONObject().put("bar", 42))); - JsonAsyncHttpClient client = new JsonAsyncHttpClient(dummy); - client.addJsonContentType(true); - client.verifyRequestContentAsJson(false); - - HttpRequest r = new HttpRequest(); - r.setPostContent(new JSONObject().put("foo", 34)); - - AsyncOperation<JsonHttpResult> result = client.execute(r); - - assertEquals(new JSONObject().put("bar", 42).toString(), result.getResult().getJson().toString()); - assertTrue(result.isSuccess()); - - result.toString(); - client.close(); - } - -} diff --git a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/LoggingAsyncHttpClientTest.java b/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/LoggingAsyncHttpClientTest.java deleted file mode 100644 index 37841f7ca29..00000000000 --- a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/LoggingAsyncHttpClientTest.java +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.clustercontroller.utils.communication.http; - -import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncOperation; -import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncOperationImpl; -import org.junit.Test; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import static org.junit.Assert.assertEquals; - -public class LoggingAsyncHttpClientTest { - - class HttpClient implements AsyncHttpClient<HttpResult> { - AsyncOperationImpl<HttpResult> lastOp; - @Override - public AsyncOperation<HttpResult> execute(HttpRequest r) { - return lastOp = new AsyncOperationImpl<>("test"); - } - @Override - public void close() { - } - } - - @Test - public void testWithoutDebugLog() { - doRequests(); - } - - @Test - public void testWithDebugLog() { - Logger log = Logger.getLogger(LoggingAsyncHttpClient.class.getName()); - log.setLevel(Level.FINE); - doRequests(); - } - - private void doRequests() { - { - HttpClient client = new HttpClient(); - LoggingAsyncHttpClient<HttpResult> loggingClient = new LoggingAsyncHttpClient<>(client); - AsyncOperation<HttpResult> op = loggingClient.execute(new HttpRequest()); - client.lastOp.setResult(new HttpResult().setContent("foo")); - assertEquals("foo", op.getResult().getContent()); - } - { - HttpClient client = new HttpClient(); - LoggingAsyncHttpClient<HttpResult> loggingClient = new LoggingAsyncHttpClient<>(client); - AsyncOperation<HttpResult> op = loggingClient.execute(new HttpRequest()); - client.lastOp.setFailure(new Exception("foo")); - assertEquals("foo", op.getCause().getMessage()); - } - } - -} diff --git a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/ProxyAsyncHttpClientTest.java b/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/ProxyAsyncHttpClientTest.java deleted file mode 100644 index 062fd4aaa32..00000000000 --- a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/ProxyAsyncHttpClientTest.java +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.clustercontroller.utils.communication.http; - -import org.codehaus.jettison.json.JSONObject; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class ProxyAsyncHttpClientTest { - - @Test - public void testSimple() throws Exception { - // Can't really test much here, but verifies that the code runs. - DummyAsyncHttpClient dummy = new DummyAsyncHttpClient( - new HttpResult().setContent(new JSONObject().put("bar", 42))); - ProxyAsyncHttpClient client = new ProxyAsyncHttpClient<>(dummy, "myproxyhost", 1234); - - HttpRequest r = new HttpRequest(); - r.setPath("/foo"); - r.setHost("myhost"); - r.setPort(4567); - - r.setPostContent(new JSONObject().put("foo", 34)); - - client.execute(r); - - assertEquals(new HttpRequest().setPath("/myhost:4567/foo") - .setHost("myproxyhost") - .setPort(1234) - .setPostContent(new JSONObject().put("foo", 34)), - dummy.lastRequest); - } - - @Test - public void testNoAndEmptyPath() throws Exception { - DummyAsyncHttpClient dummy = new DummyAsyncHttpClient( - new HttpResult().setContent(new JSONObject().put("bar", 42))); - ProxyAsyncHttpClient client = new ProxyAsyncHttpClient<>(dummy, "myproxyhost", 1234); - try{ - client.execute(new HttpRequest()); - assertTrue(false); - } catch (IllegalStateException e) { - assertTrue(e.getMessage().contains("Host and path must be set prior")); - } - client.execute(new HttpRequest().setHost("local").setPath("")); - } - -} diff --git a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/RequestQueueTest.java b/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/RequestQueueTest.java deleted file mode 100644 index 230920df53f..00000000000 --- a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/RequestQueueTest.java +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.clustercontroller.utils.communication.http; - -import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncCallback; -import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncOperation; -import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncOperationImpl; -import org.junit.Test; - -import java.util.LinkedList; - -import static org.junit.Assert.assertEquals; - -public class RequestQueueTest { - - public static class Request { - public final HttpRequest request; - public final AsyncOperationImpl<HttpResult> result; - - public Request(HttpRequest r, AsyncOperationImpl<HttpResult> rr) { - this.request = r; - this.result = rr; - } - } - - public class TestClient implements AsyncHttpClient<HttpResult> { - LinkedList<Request> requests = new LinkedList<>(); - @Override - public AsyncOperation<HttpResult> execute(HttpRequest r) { - Request p = new Request(r, new AsyncOperationImpl<HttpResult>(r.toString())); - synchronized (requests) { - requests.addLast(p); - } - return p.result; - } - @Override - public void close() {} - }; - - @Test - public void testNormalUsage() { - TestClient client = new TestClient(); - RequestQueue<HttpResult> queue = new RequestQueue<>(client, 4); - final LinkedList<HttpResult> results = new LinkedList<>(); - for (int i=0; i<10; ++i) { - queue.schedule(new HttpRequest().setPath("/" + i), new AsyncCallback<HttpResult>() { - @Override - public void done(AsyncOperation<HttpResult> op) { - if (op.isSuccess()) { - results.add(op.getResult()); - } else { - results.add(new HttpResult().setHttpCode(500, op.getCause().getMessage())); - } - } - }); - } - assertEquals(4, client.requests.size()); - for (int i=0; i<3; ++i) { - Request p = client.requests.removeFirst(); - p.result.setResult(new HttpResult()); - assertEquals(true, results.getLast().isSuccess()); - } - assertEquals(4, client.requests.size()); - for (int i=0; i<7; ++i) { - Request p = client.requests.removeFirst(); - p.result.setFailure(new Exception("Fail")); - assertEquals(false, results.getLast().isSuccess()); - } - assertEquals(0, client.requests.size()); - assertEquals(true, queue.empty()); - assertEquals(10, results.size()); - } - - public class Waiter implements Runnable { - boolean waiting = false; - boolean completed = false; - RequestQueue<HttpResult> queue; - Waiter(RequestQueue<HttpResult> queue) { - this.queue = queue; - } - public void run() { - try{ - waiting = true; - queue.waitUntilEmpty(); - } catch (InterruptedException e) { throw new Error(e); } - completed = true; - } - } - - @Test - public void testWaitUntilEmpty() throws Exception { - TestClient client = new TestClient(); - RequestQueue<HttpResult> queue = new RequestQueue<>(client, 4); - final LinkedList<HttpResult> result = new LinkedList<>(); - queue.schedule(new HttpRequest().setPath("/foo"), new AsyncCallback<HttpResult>() { - @Override - public void done(AsyncOperation<HttpResult> op) { - result.add(op.getResult()); - } - }); - Waiter waiter = new Waiter(queue); - Thread thread = new Thread(waiter); - thread.start(); - while (!waiter.waiting) { - Thread.sleep(1); - } - assertEquals(0, result.size()); - client.requests.getFirst().result.setResult(new HttpResult()); - while (!waiter.completed) { - Thread.sleep(1); - } - assertEquals(1, result.size()); - } - -} diff --git a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/TimeoutHandlerTest.java b/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/TimeoutHandlerTest.java deleted file mode 100644 index 72a2a4eab8a..00000000000 --- a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/communication/http/TimeoutHandlerTest.java +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.clustercontroller.utils.communication.http; - -import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncOperation; -import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncOperationImpl; -import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncUtils; -import com.yahoo.vespa.clustercontroller.utils.test.FakeClock; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -public class TimeoutHandlerTest { - - public class TestClient implements AsyncHttpClient<HttpResult> { - AsyncOperationImpl<HttpResult> lastOp; - @Override - public AsyncOperation<HttpResult> execute(HttpRequest r) { - return lastOp = new AsyncOperationImpl<>("test"); - } - @Override - public void close() {} - }; - - private ThreadPoolExecutor executor; - private TestClient client; - private FakeClock clock; - private TimeoutHandler<HttpResult> handler; - - @Before - public void setUp() { - executor = new ThreadPoolExecutor(10, 100, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000)); - clock = new FakeClock(); - client = new TestClient(); - handler = new TimeoutHandler<>(executor, clock, client); - } - - @After - public void tearDown() { - handler.close(); - executor.shutdown(); - } - - @Test - public void testTimeout() { - AsyncOperation<HttpResult> op = handler.execute(new HttpRequest().setTimeout(1000)); - assertFalse(op.isDone()); - clock.adjust(999); - // Give it a bit of time for timeout handler to have a chance of timout out prematurely - try{ Thread.sleep(1); } catch (InterruptedException e) {} - assertFalse(op.isDone()); - clock.adjust(1); - AsyncUtils.waitFor(op); - assertTrue(op.isDone()); - assertFalse(op.isSuccess()); - assertTrue(op.getCause().getMessage(), op.getCause().getMessage().contains("Operation timeout")); - // After timeout, finishing the original request no longer matter - client.lastOp.setResult(new HttpResult()); - assertFalse(op.isSuccess()); - assertTrue(op.getCause().getMessage(), op.getCause().getMessage().contains("Operation timeout")); - } - - @Test - public void testNoTimeout() { - AsyncOperation<HttpResult> op = handler.execute(new HttpRequest().setTimeout(1000)); - clock.adjust(999); - assertFalse(op.isDone()); - client.lastOp.setResult(new HttpResult().setContent("foo")); - AsyncUtils.waitFor(op); - assertTrue(op.isDone()); - assertTrue(op.isSuccess()); - assertEquals("foo", op.getResult().getContent()); - } - - @Test - public void testNoTimeoutFailing() { - AsyncOperation<HttpResult> op = handler.execute(new HttpRequest().setTimeout(1000)); - clock.adjust(999); - assertFalse(op.isDone()); - client.lastOp.setFailure(new Exception("foo")); - AsyncUtils.waitFor(op); - assertTrue(op.isDone()); - assertFalse(op.isSuccess()); - assertEquals("foo", op.getCause().getMessage()); - } - - @Test - public void testProvokeCompletedOpPurgeInTimeoutList() { - AsyncOperation<HttpResult> op1 = handler.execute(new HttpRequest().setTimeout(1000)); - AsyncOperationImpl<HttpResult> op1Internal = client.lastOp; - clock.adjust(300); - AsyncOperation<HttpResult> op2 = handler.execute(new HttpRequest().setTimeout(1000)); - clock.adjust(300); - op1Internal.setResult(new HttpResult().setContent("foo")); - AsyncUtils.waitFor(op1); - clock.adjust(800); - AsyncUtils.waitFor(op2); - assertEquals(true, op1.isDone()); - assertEquals(true, op2.isDone()); - assertEquals(true, op1.isSuccess()); - assertEquals(false, op2.isSuccess()); - } - - @Test - public void testNothingButGetCoverage() { - AsyncOperation<HttpResult> op = handler.execute(new HttpRequest().setTimeout(1000)); - op.getProgress(); - op.cancel(); - assertFalse(op.isCanceled()); // Cancel not currently supported - client.lastOp.setResult(new HttpResult().setContent("foo")); - AsyncUtils.waitFor(op); - op.getProgress(); - op = handler.execute(new HttpRequest().setTimeout(1000)); - handler.performTimeoutHandlerTick(); - handler.performTimeoutHandlerTick(); - client.lastOp.setResult(new HttpResult().setContent("foo")); - AsyncUtils.waitFor(op); - } - -} diff --git a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/test/AsyncHttpClient.java b/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/test/AsyncHttpClient.java new file mode 100644 index 00000000000..29f86842b34 --- /dev/null +++ b/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/test/AsyncHttpClient.java @@ -0,0 +1,18 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.clustercontroller.utils.test; + +import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncOperation; +import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpRequest; +import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpResult; + +/** + * Abstraction of an asynchronous HTTP client, such that applications don't need to depend directly on an HTTP client. + */ +public interface AsyncHttpClient<V extends HttpResult> { + + AsyncOperation<V> execute(HttpRequest r); + + /** Attempt to cancel all pending operations and shut down the client. */ + void close(); + +} diff --git a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/test/FakeClockTest.java b/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/test/FakeClockTest.java deleted file mode 100644 index 47edd7ac55c..00000000000 --- a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/test/FakeClockTest.java +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.clustercontroller.utils.test; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class FakeClockTest { - - @Test - public void testSimple() { - FakeClock clock = new FakeClock(); - // Should not start at 0, as that is common not initialized yet value - assertTrue(clock.getTimeInMillis() > 0); - long start = clock.getTimeInMillis(); - - clock.adjust(5); - assertEquals(start + 5, clock.getTimeInMillis()); - - clock.set(start + 10); - assertEquals(start + 10, clock.getTimeInMillis()); - - clock.adjust(5); - assertEquals(start + 15, clock.getTimeInMillis()); - } - - // TODO: This should probably throw exceptions.. However, that doesn't seem to be current behavior. - // I suspect some tests misuse the clock to reset things to run another test. Should probably be fixed. - @Test - public void testTurnTimeBack() { - FakeClock clock = new FakeClock(); - clock.set(1000); - - clock.set(500); - assertEquals(500, clock.getTimeInMillis()); - - clock.adjust(-100); - assertEquals(400, clock.getTimeInMillis()); - } - -} diff --git a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/test/TestTransport.java b/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/test/TestTransport.java new file mode 100644 index 00000000000..d2e76cd77f9 --- /dev/null +++ b/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/test/TestTransport.java @@ -0,0 +1,186 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.clustercontroller.utils.test; + +import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncOperation; +import com.yahoo.vespa.clustercontroller.utils.communication.async.AsyncOperationImpl; +import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpRequest; +import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpRequestHandler; +import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpResult; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +/** + * This class is a utility for unit tests.. You can register HttpRequestHandler instances in it, and then + * you can extract an AsyncHttpClient<HttpResult> instance from it, which you can use to talk to the + * registered servers. Thus you can do end to end testing of components talking over HTTP without actually + * going through HTTP if you are using the HTTP abstraction layer in communication.http package. + */ +public class TestTransport { + + private static final Logger log = Logger.getLogger(TestTransport.class.getName()); + private static class Handler { + HttpRequestHandler handler; + String pathPrefix; + Handler(HttpRequestHandler h, String prefix) { this.handler = h; this.pathPrefix = prefix; } + } + private static class Socket { + public final String hostname; + public final int port; + + Socket(String hostname, int port) { + this.hostname = hostname; + this.port = port; + } + @Override + public boolean equals(Object o) { + if (!(o instanceof Socket)) return false; + Socket other = (Socket) o; + return (hostname.equals(other.hostname) && port == other.port); + } + @Override + public int hashCode() { + return hostname.hashCode() * port; + } + } + private static class Request { + public final HttpRequest request; + public final AsyncOperationImpl<HttpResult> result; + + Request(HttpRequest r, AsyncOperationImpl<HttpResult> rr) { + this.request = r; + this.result = rr; + } + } + private final Map<Socket, List<Handler>> handlers = new HashMap<>(); + private final LinkedList<Request> requests = new LinkedList<>(); + private final AsyncHttpClient<HttpResult> client = new AsyncHttpClient<HttpResult>() { + @Override + public AsyncOperation<HttpResult> execute(HttpRequest r) { + log.fine("Queueing request " + r); + if (r.getHttpOperation() == null) { + r = r.clone(); + r.setHttpOperation(r.getPostContent() == null ? HttpRequest.HttpOp.GET : HttpRequest.HttpOp.POST); + } + r.verifyComplete(); + AsyncOperationImpl<HttpResult> op = new AsyncOperationImpl<>(r.toString()); + synchronized (requests) { + requests.addLast(new Request(r, op)); + } + return op; + } + @Override + public void close() { TestTransport.this.close(); } + }; + private boolean running = true; + private final Thread workerThread = new Thread() { + @Override + public void run() { + while (running) { + synchronized (requests) { + if (requests.isEmpty()) { + try { + requests.wait(100); + } catch (InterruptedException e) { return; } + } else { + Request request = requests.removeFirst(); + HttpRequest r = request.request; + log.fine("Processing request " + r); + HttpRequestHandler handler = getHandler(r); + if (handler == null) { + if (log.isLoggable(Level.FINE)) { + log.fine("Failed to find target for request " + r.toString(true)); + log.fine("Existing handlers:"); + for (Socket socket : handlers.keySet()) { + log.fine(" Socket " + socket.hostname + ":" + socket.port); + for (Handler h : handlers.get(socket)) { + log.fine(" " + h.pathPrefix); + } + } + } + request.result.setResult(new HttpResult().setHttpCode( + 404, "No such server socket with suitable path prefix found open")); + } else { + try{ + request.result.setResult(handler.handleRequest(r)); + } catch (Exception e) { + HttpResult result = new HttpResult().setHttpCode(500, e.getMessage()); + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw)); + result.setContent(sw.toString()); + request.result.setResult(result); + } + } + //log.fine("Request " + r.toString(true) + " created result " + request.getSecond().getResult().toString(true)); + } + } + } + } + }; + + public TestTransport() { + workerThread.start(); + } + + public void close() { + if (!running) return; + running = false; + synchronized (requests) { requests.notifyAll(); } + try { + workerThread.join(); + } catch (InterruptedException e) {} + } + + /** Get an HTTP client that talks to this test transport layer. */ + public AsyncHttpClient<HttpResult> getClient() { return client; } + + private HttpRequestHandler getHandler(HttpRequest r) { + Socket socket = new Socket(r.getHost(), r.getPort()); + synchronized (this) { + List<Handler> handlerList = handlers.get(socket); + if (handlerList == null) { + log.fine("No socket match"); + return null; + } + log.fine("Socket found"); + for (Handler h : handlers.get(socket)) { + if (r.getPath().length() >= h.pathPrefix.length() && r.getPath().substring(0, h.pathPrefix.length()).equals(h.pathPrefix)) { + return h.handler; + } + } + log.fine("No path prefix match"); + } + return null; + } + + public void addServer(HttpRequestHandler server, String hostname, int port, String pathPrefix) { + Socket socket = new Socket(hostname, port); + synchronized (this) { + List<Handler> shandlers = handlers.get(socket); + if (shandlers == null) { + shandlers = new LinkedList<>(); + handlers.put(socket, shandlers); + } + shandlers.add(new Handler(server, pathPrefix)); + } + } + + public void removeServer(HttpRequestHandler server, String hostname, int port, String pathPrefix) { + Socket socket = new Socket(hostname, port); + synchronized (this) { + List<Handler> shandlers = handlers.get(socket); + if (shandlers == null) return; + for (Handler h : shandlers) { + if (h.handler == server && h.pathPrefix.equals(pathPrefix)) { + shandlers.remove(h); + } + } + } + } + +} |