package com.limegroup.gnutella.io;
import java.nio.ByteBuffer;
import junit.framework.Test;
import com.limegroup.gnutella.connection.WriteBufferChannel;
import com.limegroup.gnutella.util.BaseTestCase;
import com.limegroup.gnutella.util.PrivilegedAccessor;
public class DelayedBufferWriterTest extends BaseTestCase {
private WriteBufferChannel source;
private WriteBufferChannel sink;
public DelayedBufferWriterTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(DelayedBufferWriterTest.class);
}
public void setUp() throws Exception {
source = new WriteBufferChannel();
sink = new WriteBufferChannel();
}
/**
* tests that the chain is created properly
*/
public void testChainCreation() throws Exception {
assertFalse(sink.status);
assertNull(sink.observer);
assertNull(source.channel);
DelayedBufferWriter delayer = new DelayedBufferWriter(1);
setupChain(delayer);
// test that when we set the sink we register that we are interested in events
assertEquals(delayer, sink.observer);
assertTrue(sink.status);
assertEquals(delayer, source.channel);
assertEquals(sink,delayer.getWriteChannel());
WriteObserver observer = (WriteObserver) PrivilegedAccessor.getValue(delayer, "observer");
assertEquals(source,observer);
}
/**
* tests that data is buffered until some time elapses
*/
public void testTimeFlush() throws Exception {
byte [] data = new byte[]{(byte)1,(byte)2};
ByteBuffer buf = ByteBuffer.wrap(data);
DelayedBufferWriter delayer = new DelayedBufferWriter(5);
setupChain(delayer);
source.setBuffer(buf);
sink.resize(5);
// data should go from the source to the buffer, but not to the sink
delayer.handleWrite();
assertEquals(2,source.position());
assertEquals(0,sink.position());
// after sleeping a while, data should move from the buffer to the sink
Thread.sleep(300);
delayer.handleWrite();
assertEquals(2,source.position());
assertEquals(2,sink.position());
// data should be 1,2
buf = sink.getBuffer();
assertEquals(1,buf.get());
assertEquals(2,buf.get());
}
/**
* tests that if the buffer is filled up it gets flushed immediately
*/
public void testForcedFlush() throws Exception {
byte [] data = new byte[]{(byte)1,(byte)2,(byte)3};
ByteBuffer buf = ByteBuffer.wrap(data);
DelayedBufferWriter delayer = new DelayedBufferWriter(2);
setupChain(delayer);
source.setBuffer(buf);
sink.resize(3);
// data the size of the buffer should immediately be flushed,
// and the rest should stay in the buffer
delayer.handleWrite();
assertEquals(3,source.position());
assertEquals(2,sink.position());
// data should be 1,2
buf = sink.getBuffer();
assertEquals(1,buf.get());
assertEquals(2,buf.get());
}
/**
* tests that the buffer always looks if there's more data available
* before writing
*/
public void testPartialBuffer() throws Exception {
byte [] data = new byte[]{(byte)1};
ByteBuffer buf = ByteBuffer.wrap(data);
DelayedBufferWriter delayer = new DelayedBufferWriter(2);
setupChain(delayer);
source.setBuffer(buf);
sink.resize(3);
// data should be buffered, and not written out
delayer.handleWrite();
assertEquals(1,source.position());
assertEquals(0,sink.position());
// add more data and sleep some time -
// on the next write signal both new and old data should go out
buf.rewind();
source.setBuffer(buf);
Thread.sleep(300);
delayer.handleWrite();
assertEquals(1,source.position());
assertEquals(2,sink.position());
// data should be 1,1
buf = sink.getBuffer();
assertEquals(1,buf.get());
assertEquals(1,buf.get());
}
/**
* tests that if nobody is interested in the buffer and its empty,
* it turns itself off from the chain
*/
public void testTurnsInterestOff() throws Exception {
byte [] data = new byte[]{(byte)1};
ByteBuffer buf = ByteBuffer.wrap(data);
DelayedBufferWriter delayer = new DelayedBufferWriter(1);
setupChain(delayer);
source.setBuffer(buf);
sink.resize(1);
delayer.handleWrite(); // source->buf and source turns itself off
Thread.sleep(300);
delayer.handleWrite(); // buf-> sink
// delayer should have turned itself off
assertFalse(sink.status);
}
private void setupChain(DelayedBufferWriter delayer) {
source.setWriteChannel(delayer);
delayer.interest(source,true);
delayer.setWriteChannel(sink);
}
}