package org.limewire.nio.channel;
import java.nio.ByteBuffer;
import java.util.Random;
import junit.framework.Test;
import org.limewire.nio.ThrottleListener;
import org.limewire.util.BaseTestCase;
import org.limewire.util.PrivilegedAccessor;
/**
* Tests that ThrottleWriter throttles data correctly.
*/
public final class ThrottleReaderTest extends BaseTestCase {
private FakeThrottle THROTTLE = new FakeThrottle();
private ReadBufferChannel SOURCE = new ReadBufferChannel();
private ThrottleReader READER = new ThrottleReader(THROTTLE, SOURCE);
private ByteBuffer BUFFER = ByteBuffer.allocate(1024);
private static Random RND = new Random();
public ThrottleReaderTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(ThrottleReaderTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
@Override
public void setUp() {
THROTTLE.clear();
}
public void testInterestAndBandwidthAvailable() throws Exception {
assertFalse(SOURCE.isInterested());
assertEquals(0, THROTTLE.interests());
READER.interestRead(false);
assertFalse(SOURCE.isInterested());
assertEquals(0, THROTTLE.interests());
READER.interestRead(true);
assertEquals(1, THROTTLE.interests());
assertFalse(SOURCE.isInterested());
bandwidthAvailable(READER);
assertTrue(SOURCE.isInterested());
}
public void testeHandleReadDataLeft() throws Exception {
// Test when data is still left after available.
// set up reader & SOURCE.
READER.interestRead(true);
bandwidthAvailable(READER);
assertTrue(SOURCE.isInterested());
// set up SOURCE & THROTTLE.
SOURCE.setBuffer(buffer(data(750)));
assertEquals(1, THROTTLE.interests());
THROTTLE.setAvailable(250);
assertFalse(THROTTLE.didRequest());
assertFalse(THROTTLE.didRelease());
doRead(BUFFER, false);
assertTrue(THROTTLE.didRequest());
assertTrue(THROTTLE.didRelease());
assertEquals(250, BUFFER.position());
assertEquals(250, SOURCE.getBuffer().position());
assertEquals(0, THROTTLE.getAvailable()); // all throttle used up.
assertEquals(500, SOURCE.getBuffer().remaining()); // data still in source
assertEquals(2, THROTTLE.interests()); // is interested in more events.
assertTrue(SOURCE.isInterested()); // channel is still interested
}
public void testHandleReadSourceEmptiesWithLeftover() throws Exception {
SOURCE.setBuffer(buffer(data(500)));
READER.interestRead(true);
bandwidthAvailable(READER);
assertEquals(1, THROTTLE.interests());
THROTTLE.setAvailable(550);
doRead(BUFFER, true);
assertEquals(500, BUFFER.position());
assertEquals(500, SOURCE.getBuffer().position());
assertEquals(0, SOURCE.getBuffer().remaining());
assertEquals(50, THROTTLE.getAvailable()); // throttle still has data
assertEquals(1, THROTTLE.interests()); // didn't request interest again.
assertFalse(SOURCE.isInterested()); // sink off.
}
public void testHandleReadSourceEmptiesExactly() throws Exception {
SOURCE.setBuffer(buffer(data(200)));
READER.interestRead(true);
bandwidthAvailable(READER);
assertEquals(1, THROTTLE.interests());
THROTTLE.setAvailable(200);
bandwidthAvailable(READER);
assertTrue(SOURCE.isInterested());
doRead(BUFFER, true);
assertEquals(1, THROTTLE.interests());
assertEquals(200, BUFFER.position());
assertEquals(200, SOURCE.getBuffer().position());
assertEquals(0, SOURCE.getBuffer().remaining());
assertEquals(0, THROTTLE.getAvailable());
assertFalse(SOURCE.isInterested());
}
public void testHandleReadSinkFills() throws Exception {
SOURCE.setBuffer(buffer(data(100)));
READER.interestRead(true);
bandwidthAvailable(READER);
assertEquals(1, THROTTLE.interests());
BUFFER.limit(75);
THROTTLE.setAvailable(300);
assertEquals(1, THROTTLE.interests());
doRead(BUFFER, false);
assertEquals(75, BUFFER.position());
assertEquals(75, SOURCE.getBuffer().position());
assertEquals(25, SOURCE.getBuffer().remaining());
assertEquals(0, BUFFER.remaining());
assertEquals(225, THROTTLE.getAvailable());
assertEquals(2, THROTTLE.interests());
assertTrue(SOURCE.isInterested());
BUFFER.limit(150);
THROTTLE.clear();
THROTTLE.setAvailable(200);
bandwidthAvailable(READER);
assertEquals(0, THROTTLE.interests());
doRead(BUFFER, true);
assertEquals(100, BUFFER.position());
assertEquals(50, BUFFER.remaining());
assertEquals(100, SOURCE.getBuffer().position());
assertEquals(0, SOURCE.getBuffer().remaining());
assertEquals(175, THROTTLE.getAvailable());
assertEquals(0, THROTTLE.interests());
assertFalse(SOURCE.isInterested());
}
public void testBandwidthAvailableWhenClosed() throws Exception {
assertFalse(SOURCE.isInterested());
READER.interestRead(true);
assertTrue(bandwidthAvailable(READER));
assertTrue(SOURCE.isInterested());
SOURCE.interestRead(false);
READER.close();
assertFalse(bandwidthAvailable(READER));
assertFalse(SOURCE.isInterested());
}
public void testInterestOffWhenNoBW() throws Exception {
assertFalse(SOURCE.isInterested());
SOURCE.setBuffer(buffer(data(100)));
READER.interestRead(true);
bandwidthAvailable(READER);
assertEquals(1, THROTTLE.interests());
THROTTLE.setAvailable(1);
ByteBuffer buf = buffer (data (10));
doRead(buf, false);
assertTrue(SOURCE.isInterested());
assertEquals(2, THROTTLE.interests());
// if there is no bandwidth available, the reader should
// turn interest in the source off
// (read calls w/o bandwidth come from the selector, not the throttle)
READER.read(buf);
assertFalse(SOURCE.isInterested());
// and interest itself for when there is bandwidth later
assertEquals(3, THROTTLE.interests());
}
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 bandwidthAvailable(Object o) throws Exception {
return ((ThrottleListener)PrivilegedAccessor.getValue(o, "throttleListener")).bandwidthAvailable();
}
private void requestBandwidth(Object o) throws Exception {
((ThrottleListener)PrivilegedAccessor.getValue(o, "throttleListener")).requestBandwidth();
}
private void releaseBandwidth(Object o) throws Exception {
((ThrottleListener)PrivilegedAccessor.getValue(o, "throttleListener")).releaseBandwidth();
}
private void doRead(ByteBuffer buffer, boolean interestOff) throws Exception {
requestBandwidth(READER);
READER.read(buffer);
if(interestOff)
READER.interestRead(false);
releaseBandwidth(READER);
}
}