package org.limewire.nio.channel; import java.nio.ByteBuffer; import java.util.Random; import junit.framework.Test; import org.limewire.util.BaseTestCase; /** * Tests that ThrottleWriter throttles data correctly. */ public final class ThrottleWriterTest extends BaseTestCase { private FakeThrottle THROTTLE = new FakeThrottle(); private WriteBufferChannel SINK = new WriteBufferChannel(1024 * 1024); private ThrottleWriter WRITER = new ThrottleWriter(THROTTLE, SINK); private static Random RND = new Random(); private WriteBufferChannel SOURCE = new WriteBufferChannel(WRITER); public ThrottleWriterTest(String name) { super(name); } public static Test suite() { return buildTestSuite(ThrottleWriterTest.class); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } @Override public void setUp() { THROTTLE.clear(); } public void testInterestAndBandwidthAvailable() throws Exception { assertFalse(SINK.interested()); assertEquals(0, THROTTLE.interests()); WRITER.interestWrite(SOURCE, false); assertFalse(SINK.interested()); assertEquals(0, THROTTLE.interests()); WRITER.interestWrite(SOURCE, true); assertEquals(1, THROTTLE.interests()); assertFalse(SINK.interested()); for(int i = 0; i < THROTTLE.listeners(); i++) THROTTLE.getListener(i).bandwidthAvailable(); assertTrue(SINK.interested()); } public void testeHandleWriteDataLeft() throws Exception { // Test when data is still left after available. // set up writer & SINK. for(int i = 0; i < THROTTLE.listeners(); i++) THROTTLE.getListener(i).bandwidthAvailable(); assertTrue(SINK.interested()); assertEquals(0, SINK.written()); // set up SOURCE & THROTTLE. SOURCE.setBuffer(buffer(data(750))); assertEquals(1, THROTTLE.interests()); THROTTLE.setAvailable(250); assertFalse(THROTTLE.didRequest()); assertFalse(THROTTLE.didRelease()); assertTrue(doWrite()); // still data left to write. assertTrue(THROTTLE.didRequest()); assertTrue(THROTTLE.didRelease()); assertEquals(250, SINK.written()); // only wrote 250 assertEquals(0, THROTTLE.getAvailable()); // all throttle used up. assertEquals(500, SOURCE.remaining()); // data still in source assertEquals(2, THROTTLE.interests()); // is interested in more events. assertFalse(SINK.interested()); // sink should not give events. } public void testHandleWriteSourceEmptiesWithLeftover() throws Exception { SOURCE.setBuffer(buffer(data(500))); assertEquals(1, THROTTLE.interests()); THROTTLE.setAvailable(550); for(int i = 0; i < THROTTLE.listeners(); i++) THROTTLE.getListener(i).bandwidthAvailable(); assertTrue(SINK.interested()); assertFalse(doWrite()); // all data written assertEquals(500, SINK.written()); // only wrote that we had. assertEquals(50, THROTTLE.getAvailable()); // throttle still has data assertEquals(1, THROTTLE.interests()); // didn't request interest again. assertFalse(SINK.interested()); // sink off. } public void testHandleWriteSourceEmptiesExactly() throws Exception { SOURCE.setBuffer(buffer(data(200))); assertEquals(1, THROTTLE.interests()); THROTTLE.setAvailable(200); for(int i = 0; i < THROTTLE.listeners(); i++) THROTTLE.getListener(i).bandwidthAvailable(); assertEquals(0, SINK.written()); assertTrue(SINK.interested()); assertFalse(doWrite()); assertEquals(1, THROTTLE.interests()); assertEquals(200, SINK.written()); assertEquals(0, THROTTLE.getAvailable()); assertEquals(0, SOURCE.remaining()); assertFalse(SINK.interested()); } public void testHandleWriteSinkFills() throws Exception { // test to make sure if sink can't take data that we release & // say we wrote it all, even if we still had stuff to write. SINK.resize(100); SOURCE.setBuffer(buffer(data(250))); THROTTLE.setAvailable(300); for(int i = 0; i < THROTTLE.listeners(); i++) THROTTLE.getListener(i).bandwidthAvailable(); assertEquals(1, THROTTLE.interests()); assertTrue(doWrite()); // data still leftover. assertEquals(100, SINK.written()); assertEquals(150, SOURCE.remaining()); assertEquals(200, THROTTLE.getAvailable()); assertEquals(2, THROTTLE.interests()); assertFalse(SINK.interested()); SINK.resize(150); THROTTLE.clear(); THROTTLE.setAvailable(200); for(int i = 0; i < THROTTLE.listeners(); i++) THROTTLE.getListener(i).bandwidthAvailable(); assertEquals(0, THROTTLE.interests()); assertFalse(doWrite()); assertEquals(150, SINK.written()); assertEquals(50, THROTTLE.getAvailable()); assertEquals(0, THROTTLE.interests()); assertFalse(SINK.interested()); } public void testBandwidthAvailableWhenClosed() throws Exception { assertFalse(SINK.interested()); for(int i = 0; i < THROTTLE.listeners(); i++) assertTrue(THROTTLE.getListener(i).bandwidthAvailable()); assertTrue(SINK.interested()); SINK.interestWrite(null, false); assertFalse(SINK.interested()); SINK.close(); for(int i = 0; i < THROTTLE.listeners(); i++) assertFalse(THROTTLE.getListener(i).bandwidthAvailable()); assertFalse(SINK.interested()); } // tests that if a handleRead is received if there is no bandwidth // interest is turned off. public void testInterestOffNoBW() throws Exception { // pretend there is bandwidth available for(int i = 0; i < THROTTLE.listeners(); i++) THROTTLE.getListener(i).bandwidthAvailable(); assertTrue(SINK.interested()); // handleWrite calls come directly from the selector // (no request/releaseBandwidth) WRITER.handleWrite(); assertFalse(SINK.interested()); } public void testeHasBufferedOutput() throws Exception { SINK.resize(10); THROTTLE.setAvailable(2); for(int i = 0; i < THROTTLE.listeners(); i++) THROTTLE.getListener(i).requestBandwidth(); assertFalse(WRITER.hasBufferedOutput()); WRITER.handleWrite(); assertFalse(WRITER.hasBufferedOutput()); assertEquals(2, WRITER.write(buffer(data(2)))); assertTrue(SINK.hasBufferedOutput()); assertTrue(WRITER.hasBufferedOutput()); SINK.getBuffer().clear(); assertFalse(WRITER.hasBufferedOutput()); assertEquals(0, WRITER.write(buffer(data(2)))); assertFalse(WRITER.hasBufferedOutput()); } private byte[] data(int size) { byte[] data = new byte[size]; RND.nextBytes(data); return data; } private ByteBuffer buffer(byte[] data) { return ByteBuffer.wrap(data); } private boolean doWrite() throws Exception { for(int i = 0; i < THROTTLE.listeners(); i++) THROTTLE.getListener(i).requestBandwidth(); boolean ret = WRITER.handleWrite(); for(int i = 0; i < THROTTLE.listeners(); i++) THROTTLE.getListener(i).releaseBandwidth(); return ret; } }