// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.jdisc;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Key;
import com.yahoo.jdisc.application.BindingMatch;
import com.yahoo.jdisc.application.UriPattern;
import com.yahoo.jdisc.handler.CompletionHandler;
import com.yahoo.jdisc.handler.ContentChannel;
import com.yahoo.jdisc.handler.RequestHandler;
import com.yahoo.jdisc.handler.ResponseHandler;
import com.yahoo.jdisc.service.BindingSetNotFoundException;
import com.yahoo.jdisc.service.CurrentContainer;
import com.yahoo.jdisc.test.TestDriver;
import org.junit.Test;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* @author Simon Thoresen
*/
public class RequestTestCase {
@Test
public void requireThatAccessorsWork() throws BindingSetNotFoundException {
MyTimer timer = new MyTimer();
timer.currentTime = 69;
TestDriver driver = TestDriver.newSimpleApplicationInstanceWithoutOsgi(timer);
driver.activateContainer(driver.newContainerBuilder());
Request request = new Request(driver, URI.create("http://foo/bar"));
assertNotNull(request);
assertEquals(URI.create("http://foo/bar"), request.getUri());
request.setUri(URI.create("http://baz/cox"));
assertEquals(URI.create("http://baz/cox"), request.getUri());
assertTrue(request.isServerRequest());
request.setServerRequest(false);
assertFalse(request.isServerRequest());
assertEquals(69, request.creationTime(TimeUnit.MILLISECONDS));
assertNull(request.getTimeout(TimeUnit.MILLISECONDS));
request.setTimeout(10, TimeUnit.MILLISECONDS);
assertNotNull(request.getTimeout(TimeUnit.MILLISECONDS));
assertEquals(10, request.timeRemaining(TimeUnit.MILLISECONDS).longValue());
assertTrue(request.context().isEmpty());
assertTrue(request.headers().isEmpty());
TimeoutManager timeoutManager = new MyTimeoutManager();
request.setTimeoutManager(timeoutManager);
assertSame(timeoutManager, request.getTimeoutManager());
request.release();
assertTrue(driver.close());
}
@Test
public void requireThatCancelWorks() {
MyTimer timer = new MyTimer();
TestDriver driver = TestDriver.newSimpleApplicationInstanceWithoutOsgi(timer);
Request request = newRequest(driver);
assertFalse(request.isCancelled());
request.cancel();
assertTrue(request.isCancelled());
request.release();
assertTrue(driver.close());
}
@Test
public void requireThatDefaultTimeoutIsInfinite() {
MyTimer timer = new MyTimer();
TestDriver driver = TestDriver.newSimpleApplicationInstanceWithoutOsgi(timer);
Request request = newRequest(driver);
assertNull(request.getTimeout(TimeUnit.MILLISECONDS));
assertNull(request.timeRemaining(TimeUnit.MILLISECONDS));
assertFalse(request.isCancelled());
timer.currentTime = Long.MAX_VALUE;
assertFalse(request.isCancelled());
request.release();
assertTrue(driver.close());
}
@Test
public void requireThatTimeRemainingUsesTimer() {
MyTimer timer = new MyTimer();
TestDriver driver = TestDriver.newSimpleApplicationInstanceWithoutOsgi(timer);
Request request = newRequest(driver);
request.setTimeout(10, TimeUnit.MILLISECONDS);
for (timer.currentTime = 0; timer.currentTime <= request.getTimeout(TimeUnit.MILLISECONDS);
++timer.currentTime)
{
assertEquals(request.getTimeout(TimeUnit.MILLISECONDS) - timer.currentTime,
request.timeRemaining(TimeUnit.MILLISECONDS).longValue());
}
request.release();
assertTrue(driver.close());
}
@Test
public void requireThatTimeoutCausesCancel() {
MyTimer timer = new MyTimer();
TestDriver driver = TestDriver.newSimpleApplicationInstanceWithoutOsgi(timer);
Request request = newRequest(driver);
request.setTimeout(10, TimeUnit.MILLISECONDS);
assertFalse(request.isCancelled());
timer.currentTime = 10;
assertTrue(request.isCancelled());
request.release();
assertTrue(driver.close());
}
@Test
public void requireThatCancelIsTrueIfParentIsCancelled() {
TestDriver driver = TestDriver.newSimpleApplicationInstanceWithoutOsgi();
Request parent = newRequest(driver);
Request child = new Request(parent, URI.create("http://localhost/"));
parent.cancel();
assertTrue(child.isCancelled());
parent.release();
child.release();
assertTrue(driver.close());
}
@Test
public void requireThatDestroyReleasesContainer() {
final MyContainer container = new MyContainer();
Request request = new Request(new CurrentContainer() {
@Override
public Container newReference(URI uri) {
return container;
}
}, URI.create("http://localhost/"));
assertEquals(1, container.refCount);
request.release();
assertEquals(0, container.refCount);
}
@Test
public void requireThatServerConnectResolvesToServerBinding() {
MyContainer container = new MyContainer();
Request request = new Request(container, URI.create("http://localhost/"));
request.connect(new MyResponseHandler());
assertNotNull(container.asServer);
assertTrue(container.asServer);
}
@Test
public void requireThatClientConnectResolvesToClientBinding() {
MyContainer container = new MyContainer();
Request serverReq = new Request(container, URI.create("http://localhost/"));
Request clientReq = new Request(serverReq, URI.create("http://localhost/"));
clientReq.connect(new MyResponseHandler());
assertNotNull(container.asServer);
assertFalse(container.asServer);
}
@Test
public void requireThatNullTimeoutManagerThrowsException() {
TestDriver driver = TestDriver.newSimpleApplicationInstanceWithoutOsgi();
Request request = newRequest(driver);
try {
request.setTimeoutManager(null);
fail();
} catch (NullPointerException e) {
}
request.release();
assertTrue(driver.close());
}
@Test
public void requireThatTimeoutManagerCanNotBeReplaced() {
TestDriver driver = TestDriver.newSimpleApplicationInstanceWithoutOsgi();
Request request = newRequest(driver);
TimeoutManager manager = new MyTimeoutManager();
request.setTimeoutManager(manager);
try {
request.setTimeoutManager(manager);
fail();
} catch (IllegalStateException e) {
assertEquals("Timeout manager already set.", e.getMessage());
}
request.release();
assertTrue(driver.close());
}
@Test
public void requireThatSetTimeoutCallsTimeoutManager() {
TestDriver driver = TestDriver.newSimpleApplicationInstanceWithoutOsgi();
Request request = newRequest(driver);
MyTimeoutManager timeoutManager = new MyTimeoutManager();
request.setTimeoutManager(timeoutManager);
request.setTimeout(6, TimeUnit.SECONDS);
assertEquals(6000, timeoutManager.timeoutMillis);
request.release();
assertTrue(driver.close());
}
@Test
public void requireThatSetTimeoutManagerPropagatesCurrentTimeout() {
TestDriver driver = TestDriver.newSimpleApplicationInstanceWithoutOsgi();
Request request = newRequest(driver);
MyTimeoutManager timeoutManager = new MyTimeoutManager();
request.setTimeout(6, TimeUnit.SECONDS);
request.setTimeoutManager(timeoutManager);
assertEquals(6000, timeoutManager.timeoutMillis);
request.release();
assertTrue(driver.close());
}
@Test
public void requireThatUriIsNormalized() {
TestDriver driver = TestDriver.newSimpleApplicationInstanceWithoutOsgi();
driver.activateContainer(driver.newContainerBuilder());
assertUri(driver, "http://host/foo", "http://host/foo");
assertUri(driver, "http://host/./foo", "http://host/foo");
assertUri(driver, "http://host/././foo", "http://host/foo");
assertUri(driver, "http://host/foo/", "http://host/foo/");
assertUri(driver, "http://host/foo/.", "http://host/foo/");
assertUri(driver, "http://host/foo/./", "http://host/foo/");
assertUri(driver, "http://host/foo/./.", "http://host/foo/");
assertUri(driver, "http://host/foo/././", "http://host/foo/");
assertUri(driver, "http://host/foo/..", "http://host/");
assertUri(driver, "http://host/foo/../", "http://host/");
assertUri(driver, "http://host/foo/../bar", "http://host/bar");
assertUri(driver, "http://host/foo/../bar/", "http://host/bar/");
assertUri(driver, "http://host//foo//", "http://host/foo/");
assertUri(driver, "http://host///foo///", "http://host/foo/");
assertUri(driver, "http://host///foo///bar///", "http://host/foo/bar/");
assertTrue(driver.close());
}
private static void assertUri(CurrentContainer container, String requestUri, String expectedUri) {
Request serverReq = new Request(container, URI.create(requestUri));
assertEquals(expectedUri, serverReq.getUri().toString());
serverReq.setUri(URI.create(requestUri));
assertEquals(expectedUri, serverReq.getUri().toString());
Request clientReq = new Request(serverReq, URI.create(requestUri));
assertEquals(expectedUri, clientReq.getUri().toString());
serverReq.release();
clientReq.release();
}
private static Request newRequest(TestDriver driver) {
driver.activateContainer(driver.newContainerBuilder());
return new Request(driver, URI.create("http://host/path"));
}
private static class MyTimer extends AbstractModule implements Timer {
long currentTime = 0;
@Override
public long currentTimeMillis() {
return currentTime;
}
@Override
protected void configure() {
bind(Timer.class).toInstance(this);
}
}
private static class MyContainer implements CurrentContainer, Container {
Boolean asServer = null;
int refCount = 1;
@Override
public Container newReference(URI uri) {
return this;
}
@Override
public RequestHandler resolveHandler(Request request) {
this.asServer = request.isServerRequest();
RequestHandler requestHandler = new MyRequestHandler();
request.setBindingMatch(new BindingMatch<>(
new UriPattern("http://*/*").match(request.getUri()),
requestHandler));
return requestHandler;
}
@Override
public T getInstance(Key key) {
return Guice.createInjector().getInstance(key);
}
@Override
public T getInstance(Class type) {
return Guice.createInjector().getInstance(type);
}
@Override
public ResourceReference refer() {
++refCount;
return new ResourceReference() {
@Override
public void close() {
--refCount;
}
};
}
@Override
public void release() {
--refCount;
}
@Override
public long currentTimeMillis() {
return 0;
}
}
private static class MyRequestHandler extends NoopSharedResource implements RequestHandler {
@Override
public ContentChannel handleRequest(Request request, ResponseHandler handler) {
return new MyContentChannel();
}
@Override
public void handleTimeout(Request request, ResponseHandler handler) {
}
}
private static class MyResponseHandler implements ResponseHandler {
@Override
public ContentChannel handleResponse(Response response) {
return null;
}
}
private static class MyContentChannel implements ContentChannel {
@Override
public void write(ByteBuffer buf, CompletionHandler handler) {
}
@Override
public void close(CompletionHandler handler) {
}
}
private static class MyTimeoutManager implements TimeoutManager {
long timeoutMillis;
@Override
public void scheduleTimeout(Request request) {
timeoutMillis = request.getTimeout(TimeUnit.MILLISECONDS);
}
}
}