package org.webpieces.nio.test.fullcontrol;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import junit.framework.TestCase;
import org.webpieces.nio.api.channels.TCPChannel;
import org.webpieces.nio.api.deprecated.ChannelManagerOld;
import org.webpieces.nio.api.deprecated.ChannelService;
import org.webpieces.nio.api.deprecated.ChannelServiceFactory;
import org.webpieces.nio.api.handlers.DataListener;
import org.webpieces.nio.api.handlers.OperationCallback;
import org.webpieces.nio.api.libs.BufferFactory;
import org.webpieces.nio.api.libs.BufferHelper;
import org.webpieces.nio.api.libs.FactoryCreator;
import org.webpieces.nio.api.testutil.CloneByteBuffer;
import org.webpieces.nio.api.testutil.HandlerForTests;
import org.webpieces.nio.api.testutil.chanapi.ChannelsFactory;
import org.webpieces.nio.api.testutil.chanapi.SocketChannel;
import org.webpieces.nio.api.testutil.nioapi.ChannelRegistrationListener;
import org.webpieces.nio.api.testutil.nioapi.Select;
import org.webpieces.nio.api.testutil.nioapi.SelectorListener;
import org.webpieces.nio.api.testutil.nioapi.SelectorProviderFactory;
import biz.xsoftware.mock.CalledMethod;
import biz.xsoftware.mock.CloningBehavior;
import biz.xsoftware.mock.MockObject;
import biz.xsoftware.mock.MockObjectFactory;
public class TestWrites extends TestCase {
//private static final Logger log = LoggerFactory.getLogger(TestWrites.class);
private static final BufferHelper HELPER = ChannelServiceFactory.bufferHelper(null);
private BufferFactory bufFactory;
private ChannelService chanMgr;
private MockObject mockHandler;
//private MockObject mockConnect;
private TCPChannel client1;
private ChannelServiceFactory factory;
private MockObject mockSunsChannel;
private MockObject mockSelect;
private MockObject mockRegListener;
private MockObject mockWriteHandler;
private SelectorListener listener;
public TestWrites(String name) {
super(name);
}
protected void setUp() throws Exception {
HandlerForTests.setupLogging();
if(bufFactory == null) {
Map<String, Object> map = new HashMap<String, Object>();
map.put(FactoryCreator.KEY_IS_DIRECT, false);
FactoryCreator creator = FactoryCreator.createFactory(null);
bufFactory = creator.createBufferFactory(map);
}
mockSunsChannel = MockObjectFactory.createMock(SocketChannel.class);
mockSunsChannel.addIgnore("isBlocking");
mockSunsChannel.addIgnore("getSelectableChannel");
mockSunsChannel.setDefaultReturnValue("isBlocking", false);
mockSunsChannel.addReturnValue("connect", true);
mockSelect = MockObjectFactory.createMock(Select.class);
mockSelect.addIgnore("isRunning");
mockSelect.addIgnore("getThread");
mockSelect.addIgnore("setRunning");
mockSelect.setDefaultReturnValue("isRunning", true);
mockSelect.setDefaultReturnValue("isWantShutdown", false);
mockWriteHandler = MockObjectFactory.createMock(OperationCallback.class);
mockRegListener = MockObjectFactory.createMock(ChannelRegistrationListener.class);
MockObject mockChannels = MockObjectFactory.createMock(ChannelsFactory.class);
MockObject mockSelectorProv = MockObjectFactory.createMock(SelectorProviderFactory.class);
ChannelServiceFactory basic = ChannelServiceFactory.createFactory(null);
Map<String, Object> props2 = new HashMap<String, Object>();
props2.put(ChannelServiceFactory.KEY_IMPLEMENTATION_CLASS, ChannelServiceFactory.VAL_EXCEPTION_CHANNEL_MGR);
props2.put(ChannelServiceFactory.KEY_CHILD_CHANNELMGR_FACTORY, basic);
factory = ChannelServiceFactory.createFactory(props2);
Map<String, Object> p = new HashMap<String, Object>();
p.put(ChannelManagerOld.KEY_ID, "[client]");
p.put(ChannelManagerOld.KEY_BUFFER_FACTORY, bufFactory);
p.put("mock.channelsFactory", mockChannels);
p.put("mock.selectorProvider", mockSelectorProv);
chanMgr = factory.createChannelManager(p);
mockSelectorProv.addReturnValue("provider", mockSelect);
chanMgr.start();
CalledMethod m = mockSelect.expect("startPollingThread");
listener = (SelectorListener)m.getAllParams()[0];
mockHandler = MockObjectFactory.createMock(DataListener.class);
mockHandler.setDefaultBehavior("incomingData", new CloneByteBuffer());
//mockConnect = MockObjectFactory.createMock(ConnectCallback.class);
mockChannels.addReturnValue("open", mockSunsChannel);
client1 = chanMgr.createTCPChannel("ClientChannel", null);
mockSunsChannel.expect("configureBlocking");
}
protected void tearDown() throws Exception {
mockSunsChannel.expect(MockObject.NONE);
//mockSelect.expect(MockObject.NONE);
HandlerForTests.checkForWarnings();
}
public void testSomething() {
}
public void xxtestBasicWrite() throws Exception {
client1.oldConnect(null);
mockSunsChannel.expect("connect");
runBasic();
}
private void runBasic() throws IOException
{
mockSelect.setDefaultReturnValue("getThread", null);
mockSunsChannel.setDefaultBehavior("write", new CloneByteBuffer());
ByteBuffer b = ByteBuffer.allocate(1000);
String expected = "abc";
HELPER.putString(b, expected);
HELPER.doneFillingBuffer(b);
// mockSunsChannel.addReturnValue("write", b.remaining());
client1.oldWrite(b);
CalledMethod m = mockSunsChannel.expect("write");
ByteBuffer actual = (ByteBuffer)m.getAllParams()[0];
String msg = HELPER.readString(actual, actual.remaining());
assertEquals(expected, msg);
}
public void xxtestAsynchWrite() throws Exception {
mockSelect.setDefaultReturnValue("getThread", Thread.currentThread());
MySelectableChannel channel = new MySelectableChannel((SocketChannel)mockSunsChannel);
MyKey key = new MyKey(channel);
mockSunsChannel.setDefaultReturnValue("getSelectableChannel", channel);
MockObject mockKey = key.getMock();
mockKey.setDefaultReturnValue("channel", mockSunsChannel);
mockKey.setDefaultReturnValue("readyOps", SelectionKey.OP_WRITE);
mockSunsChannel.setDefaultBehavior("write", new NoReadByteBuffer2(0));
client1.oldConnect(null);
mockSunsChannel.expect("connect");
ByteBuffer b = ByteBuffer.allocate(1000);
String expected = "abc";
HELPER.putString(b, expected);
HELPER.doneFillingBuffer(b);
mockSelect.addReturnValue("createRegistrationListener", mockRegListener);
mockSunsChannel.addReturnValue("write", 0);
client1.oldWrite(b, (OperationCallback)mockWriteHandler);
mockSunsChannel.expect("write");
mockSelect.setDefaultReturnValue("getKeyFromChannel", key);
String[] methodNames = new String[] { "getKeyFromChannel", "register" };
CalledMethod[] methods = mockSelect.expect(methodNames);
Object attachment = methods[1].getAllParams()[2];
key.attach(attachment);
Set<SelectionKey> set = new HashSet<SelectionKey>();
set.add(key);
mockSelect.addReturnValue("select", 1);
mockSelect.addReturnValue("selectedKeys", set);
mockKey.addReturnValue("interestOps", SelectionKey.OP_WRITE);
mockSunsChannel.addReturnValue("write", b.remaining());
//now, simlute the jdk selector going off....
listener.selectorFired();
CalledMethod m = mockSunsChannel.expect("write");
ByteBuffer actual = (ByteBuffer)m.getAllParams()[0];
String msg = HELPER.readString(actual, actual.remaining());
assertEquals(expected, msg);
}
/**
* This tests the situation where client writes something which can't be written and
* so that gets queued, and then client writes another thing which gets queued. finally
* the selector is fired, and this tests that both buffers were written.
*
* @throws Exception
*/
public void xxtestQueuedAsynchWrite() throws Exception {
mockSelect.setDefaultReturnValue("getThread", Thread.currentThread());
MySelectableChannel channel = new MySelectableChannel((SocketChannel)mockSunsChannel);
MyKey key = new MyKey(channel);
mockSunsChannel.setDefaultReturnValue("getSelectableChannel", channel);
MockObject mockKey = key.getMock();
mockKey.addIgnore("readyOps");
mockKey.setDefaultReturnValue("channel", mockSunsChannel);
mockKey.setDefaultReturnValue("readyOps", SelectionKey.OP_WRITE);
//mockSunsChannel.addBehavior("write", new NoReadByteBuffer2());
//mockSunsChannel.addBehavior("write", new CloneByteBuffer());
String expected = "abc";
String expected2 = "def";
mockKey.addReturnValue("interestOps", SelectionKey.OP_WRITE);
fireSelector(key, expected, expected2, false);
String[] methodNames = new String[] { "write", "write" };
CalledMethod[] methods = mockSunsChannel.expect(methodNames);
ByteBuffer actual = (ByteBuffer)methods[0].getAllParams()[0];
String msg = HELPER.readString(actual, actual.remaining());
assertEquals(expected, msg);
ByteBuffer actual2 = (ByteBuffer)methods[1].getAllParams()[0];
msg = HELPER.readString(actual2, actual2.remaining());
assertEquals(expected2, msg);
//expect that an unregistration happened
methodNames = new String[] { "interestOps" , "interestOps"};
methods = mockKey.expect(methodNames);
//expect that this channel is no longer interested in anything
int ops = (Integer)methods[1].getAllParams()[0];
assertEquals(0, ops);
//make sure data can flow through as usual...
runBasic();
}
public int fireSelector(MyKey key, String expected, String expected2, boolean isSpecial) throws Exception {
client1.oldConnect(null);
mockSunsChannel.expect("connect");
ByteBuffer b = ByteBuffer.allocate(1000);
HELPER.putString(b, expected);
HELPER.doneFillingBuffer(b);
int remain1 = b.remaining();
mockSelect.addReturnValue("createRegistrationListener", mockRegListener);
mockSunsChannel.addBehavior("write", new NoReadByteBuffer2(0));
client1.oldWrite(b, (OperationCallback)mockWriteHandler);
mockSunsChannel.expect("write");
b = ByteBuffer.allocate(50);
int remain2 = b.remaining();
HELPER.putString(b, expected2);
HELPER.doneFillingBuffer(b);
client1.oldWrite(b, (OperationCallback)mockWriteHandler);
mockSunsChannel.expect(MockObject.NONE);
mockSelect.setDefaultReturnValue("getKeyFromChannel", key);
String[] methodNames = new String[] { "getKeyFromChannel", "register" };
CalledMethod[] methods = mockSelect.expect(methodNames);
Object attachment = methods[1].getAllParams()[2];
key.attach(attachment);
Set<SelectionKey> set = new HashSet<SelectionKey>();
set.add(key);
mockSelect.addReturnValue("select", 1);
mockSelect.addReturnValue("selectedKeys", set);
mockSunsChannel.addBehavior("write", new NoReadByteBuffer2(remain1));
if(isSpecial)
mockSunsChannel.addBehavior("write", new NoReadByteBuffer2(1));
else
mockSunsChannel.addBehavior("write", new NoReadByteBuffer2(remain2));
//now, simlute the jdk selector going off....
listener.selectorFired();
return remain2;
}
/**
* Have client do 3 writes, have the jdk not write at first causing writes to be
* queued. Then have 1.5 writes happen causing the channel to stay registered
* for writes. fire the selector and write the rest out.
*/
public void xxtestDelayedAsynchWrite() throws Exception {
mockSelect.setDefaultReturnValue("getThread", Thread.currentThread());
MySelectableChannel channel = new MySelectableChannel((SocketChannel)mockSunsChannel);
MyKey key = new MyKey(channel);
mockSunsChannel.setDefaultReturnValue("getSelectableChannel", channel);
MockObject mockKey = key.getMock();
mockKey.addIgnore("readyOps");
mockKey.setDefaultReturnValue("channel", mockSunsChannel);
mockKey.setDefaultReturnValue("readyOps", SelectionKey.OP_WRITE);
//mockSunsChannel.setDefaultBehavior("write", new CloneForDelayedWrite());
String expected = "abc";
String expected2 = "def";
int remain2 = fireSelector(key, expected, expected2, true);
String[] methodsNames = new String[] { "write", "write" };
CalledMethod[] methods = mockSunsChannel.expect(methodsNames);
ByteBuffer actual = (ByteBuffer)methods[0].getAllParams()[0];
String msg = HELPER.readString(actual, actual.remaining());
assertEquals(expected, msg);
//because cache1 was a snapshot of what was passed in, we need to modify it...
ByteBuffer cache1 = (ByteBuffer)methods[1].getAllParams()[0];
cache1.limit(1);
ByteBuffer b3 = ByteBuffer.allocate(50);
int remain3 = b3.remaining();
String expected3 = "ghi";
HELPER.putString(b3, expected3);
HELPER.doneFillingBuffer(b3);
client1.oldWrite(b3, (OperationCallback)mockWriteHandler);
Set<SelectionKey> set = new HashSet<SelectionKey>();
set.add(key);
mockSelect.addReturnValue("select", 1);
mockSelect.addReturnValue("selectedKeys", set);
//mockKey.addReturnValue("interestOps", SelectionKey.OP_WRITE);
mockSunsChannel.addBehavior("write", new NoReadByteBuffer2(remain2));
mockSunsChannel.addBehavior("write", new NoReadByteBuffer2(remain3));
mockKey.addReturnValue("interestOps", SelectionKey.OP_WRITE);
//fire the selector again....
listener.selectorFired();
methods = mockSunsChannel.expect(methodsNames);
ByteBuffer cache2 = (ByteBuffer)methods[0].getAllParams()[0];
ByteBuffer actual2 = ByteBuffer.allocate(20);
actual2.put(cache1);
actual2.put(cache2);
HELPER.doneFillingBuffer(actual2);
String msg2 = HELPER.readString(actual2, actual2.remaining());
assertEquals(expected2, msg2);
ByteBuffer actual3 = (ByteBuffer)methods[1].getAllParams()[0];
String msg3 = HELPER.readString(actual3, actual3.remaining());
assertEquals(expected3, msg3);
//expect that an unregistration happened
String[] methodNames = new String[] { "interestOps", "interestOps" };
methods = mockKey.expect(methodNames);
//expect that this channel is no longer interested in anything
int ops = (Integer)methods[1].getAllParams()[0];
assertEquals(0, ops);
//make sure data can flow through as usual...
runBasic();
}
/**
* Test exceptions on all tests above this one and make sure a failure
* event is fired to the client.
*/
public void testExcepitons() {
}
private static final class NoReadByteBuffer2 implements CloningBehavior {
private int numReadBytes;
private NoReadByteBuffer2(int numReadBytes) {
this.numReadBytes = numReadBytes;
}
public Object[] writeCloner(ByteBuffer b) {
return new Object[] { CloneByteBuffer.cloneWithoutModify(b) };
}
public int write(ByteBuffer b) {
if(numReadBytes == 0)
return 0;
if(b.remaining() < numReadBytes) {
numReadBytes = b.remaining();
}
byte[] data = new byte[numReadBytes];
b.get(data);
return numReadBytes;
}
}
}