| // |
| // ======================================================================== |
| // 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)); |
| } |
| } |