blob: f6cefa12e9bb23b44493ec01b000b46ff3e33d08 [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.io;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
import org.eclipse.jetty.toolchain.test.annotation.Slow;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.thread.Scheduler;
import org.eclipse.jetty.util.thread.TimerScheduler;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AdvancedRunner.class)
public class ByteArrayEndPointTest
{
private Scheduler _scheduler;
@Before
public void before() throws Exception
{
_scheduler = new TimerScheduler();
_scheduler.start();
}
@After
public void after() throws Exception
{
_scheduler.stop();
}
@Test
public void testFill() throws Exception
{
ByteArrayEndPoint endp = new ByteArrayEndPoint();
endp.setInput("test input");
ByteBuffer buffer = BufferUtil.allocate(1024);
assertEquals(10,endp.fill(buffer));
assertEquals("test input",BufferUtil.toString(buffer));
assertEquals(0,endp.fill(buffer));
endp.setInput(" more");
assertEquals(5,endp.fill(buffer));
assertEquals("test input more",BufferUtil.toString(buffer));
assertEquals(0,endp.fill(buffer));
endp.setInput((ByteBuffer)null);
assertEquals(-1,endp.fill(buffer));
endp.close();
try
{
endp.fill(buffer);
fail();
}
catch(IOException e)
{
assertThat(e.getMessage(),containsString("CLOSED"));
}
endp.reset();
endp.setInput("and more");
buffer = BufferUtil.allocate(4);
assertEquals(4,endp.fill(buffer));
assertEquals("and ",BufferUtil.toString(buffer));
assertEquals(0,endp.fill(buffer));
BufferUtil.clear(buffer);
assertEquals(4,endp.fill(buffer));
assertEquals("more",BufferUtil.toString(buffer));
}
@Test
public void testGrowingFlush() throws Exception
{
ByteArrayEndPoint endp = new ByteArrayEndPoint((byte[])null,15);
endp.setGrowOutput(true);
assertEquals(true,endp.flush(BufferUtil.toBuffer("some output")));
assertEquals("some output",endp.getOutputString());
assertEquals(true,endp.flush(BufferUtil.toBuffer(" some more")));
assertEquals("some output some more",endp.getOutputString());
assertEquals(true,endp.flush());
assertEquals("some output some more",endp.getOutputString());
assertEquals(true,endp.flush(BufferUtil.EMPTY_BUFFER));
assertEquals("some output some more",endp.getOutputString());
assertEquals(true,endp.flush(BufferUtil.EMPTY_BUFFER,BufferUtil.toBuffer(" and"),BufferUtil.toBuffer(" more")));
assertEquals("some output some more and more",endp.getOutputString());
endp.close();
}
@Test
public void testFlush() throws Exception
{
ByteArrayEndPoint endp = new ByteArrayEndPoint((byte[])null,15);
endp.setGrowOutput(false);
endp.setOutput(BufferUtil.allocate(10));
ByteBuffer data = BufferUtil.toBuffer("Some more data.");
assertEquals(false,endp.flush(data));
assertEquals("Some more ",endp.getOutputString());
assertEquals("data.",BufferUtil.toString(data));
assertEquals("Some more ",endp.takeOutputString());
assertEquals(true,endp.flush(data));
assertEquals("data.",BufferUtil.toString(endp.takeOutput()));
endp.close();
}
@Test
public void testReadable() throws Exception
{
ByteArrayEndPoint endp = new ByteArrayEndPoint(_scheduler, 5000);
endp.setInput("test input");
ByteBuffer buffer = BufferUtil.allocate(1024);
FutureCallback fcb = new FutureCallback();
endp.fillInterested(fcb);
assertTrue(fcb.isDone());
assertEquals(null, fcb.get());
assertEquals(10, endp.fill(buffer));
assertEquals("test input", BufferUtil.toString(buffer));
fcb = new FutureCallback();
endp.fillInterested(fcb);
assertFalse(fcb.isDone());
assertEquals(0, endp.fill(buffer));
endp.setInput(" more");
assertTrue(fcb.isDone());
assertEquals(null, fcb.get());
assertEquals(5, endp.fill(buffer));
assertEquals("test input more", BufferUtil.toString(buffer));
fcb = new FutureCallback();
endp.fillInterested(fcb);
assertFalse(fcb.isDone());
assertEquals(0, endp.fill(buffer));
endp.setInput((ByteBuffer)null);
assertTrue(fcb.isDone());
assertEquals(null, fcb.get());
assertEquals(-1, endp.fill(buffer));
fcb = new FutureCallback();
endp.fillInterested(fcb);
assertTrue(fcb.isDone());
assertEquals(null, fcb.get());
assertEquals(-1, endp.fill(buffer));
endp.close();
fcb = new FutureCallback();
endp.fillInterested(fcb);
assertTrue(fcb.isDone());
try
{
fcb.get();
fail();
}
catch (ExecutionException e)
{
assertThat(e.toString(), containsString("Closed"));
}
}
@Test
public void testWrite() throws Exception
{
ByteArrayEndPoint endp = new ByteArrayEndPoint(_scheduler, 5000, (byte[])null, 15);
endp.setGrowOutput(false);
endp.setOutput(BufferUtil.allocate(10));
ByteBuffer data = BufferUtil.toBuffer("Data.");
ByteBuffer more = BufferUtil.toBuffer(" Some more.");
FutureCallback fcb = new FutureCallback();
endp.write( fcb, data);
assertTrue(fcb.isDone());
assertEquals(null, fcb.get());
assertEquals("Data.", endp.getOutputString());
fcb = new FutureCallback();
endp.write(fcb, more);
assertFalse(fcb.isDone());
assertEquals("Data. Some", endp.getOutputString());
assertEquals("Data. Some", endp.takeOutputString());
assertTrue(fcb.isDone());
assertEquals(null, fcb.get());
assertEquals(" more.", endp.getOutputString());
endp.close();
}
/**
* Simulate AbstractConnection.ReadCallback.failed()
*/
public static class Closer extends FutureCallback
{
private EndPoint endp;
public Closer(EndPoint endp)
{
this.endp = endp;
}
@Override
public void failed(Throwable cause)
{
endp.close();
super.failed(cause);
}
}
@Slow
@Test
public void testIdle() throws Exception
{
long idleTimeout = 500;
ByteArrayEndPoint endp = new ByteArrayEndPoint(_scheduler, idleTimeout);
endp.setInput("test");
endp.setGrowOutput(false);
endp.setOutput(BufferUtil.allocate(5));
// no idle check
assertTrue(endp.isOpen());
Thread.sleep(idleTimeout * 2);
assertTrue(endp.isOpen());
// normal read
ByteBuffer buffer = BufferUtil.allocate(1024);
FutureCallback fcb = new FutureCallback();
endp.fillInterested(fcb);
assertTrue(fcb.isDone());
assertEquals(null, fcb.get());
assertEquals(4, endp.fill(buffer));
assertEquals("test", BufferUtil.toString(buffer));
// read timeout
fcb = new FutureCallback();
endp.fillInterested(fcb);
long start = System.currentTimeMillis();
try
{
fcb.get();
fail();
}
catch (ExecutionException t)
{
assertThat(t.getCause(), instanceOf(TimeoutException.class));
}
assertThat(System.currentTimeMillis() - start, greaterThan(idleTimeout / 2));
assertThat("Endpoint open", endp.isOpen(), is(true));
// We need to delay the write timeout test below from the read timeout test above.
// The reason is that the scheduler thread that fails the endPoint WriteFlusher
// because of the read timeout above runs concurrently with the write below, and
// if it runs just after the write below, the test fails because the write callback
// below fails immediately rather than after the idle timeout.
Thread.sleep(idleTimeout / 2);
// write timeout
fcb = new FutureCallback();
endp.write(fcb, BufferUtil.toBuffer("This is too long"));
start = System.currentTimeMillis();
try
{
fcb.get();
fail();
}
catch (ExecutionException t)
{
assertThat(t.getCause(), instanceOf(TimeoutException.class));
}
assertThat(System.currentTimeMillis() - start, greaterThan(idleTimeout / 2));
assertThat("Endpoint open", endp.isOpen(), is(true));
endp.fillInterested(new Closer(endp));
// Still no idle close (wait half the time)
Thread.sleep(idleTimeout / 2);
assertThat("Endpoint open", endp.isOpen(), is(true));
// shutdown out
endp.shutdownOutput();
// idle close (wait double the time)
Thread.sleep(idleTimeout * 2);
assertThat("Endpoint open", endp.isOpen(), is(false));
}
}