package org.threadly.litesockets.tcp;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.threadly.concurrent.PriorityScheduler;
import org.threadly.concurrent.future.FutureUtils;
import org.threadly.concurrent.future.ListenableFuture;
import org.threadly.litesockets.Client;
import org.threadly.litesockets.Client.Reader;
import org.threadly.litesockets.buffers.MergedByteBuffers;
import org.threadly.litesockets.SocketExecuter;
import org.threadly.litesockets.TCPClient;
import org.threadly.litesockets.TCPServer;
import org.threadly.litesockets.ThreadedSocketExecuter;
import org.threadly.litesockets.utils.PortUtils;
import org.threadly.test.concurrent.TestCondition;
public class TCPTests {
private static final String OS = System.getProperty("os.name").toLowerCase();
public static final String SMALL_TEXT = "TEST111";
public static final ByteBuffer SMALL_TEXT_BUFFER = ByteBuffer.wrap(SMALL_TEXT.getBytes());
public static final String LARGE_TEXT;
public static final ByteBuffer LARGE_TEXT_BUFFER;
static {
StringBuffer sb = new StringBuffer();
for(int i = 0; i<20000; i++) {
sb.append(SMALL_TEXT);
}
LARGE_TEXT = sb.toString();
LARGE_TEXT_BUFFER = ByteBuffer.wrap(LARGE_TEXT.getBytes());
}
PriorityScheduler PS;
int port;
final String GET = "hello";
SocketExecuter SE;
TCPServer server;
FakeTCPServerClient serverFC;
@Before
public void start() throws IOException {
port = PortUtils.findTCPPort();
PS = new PriorityScheduler(5);
SE = new ThreadedSocketExecuter(PS);
SE.start();
serverFC = new FakeTCPServerClient();
server = SE.createTCPServer("localhost", port);
server.setClientAcceptor(serverFC);
server.addCloseListener(serverFC);
server.start();
}
@After
public void stop() throws Exception{
serverFC = null;
Runtime.getRuntime().gc();
Runtime.getRuntime().gc();
SE.stopIfRunning();
PS.shutdownNow();
server.stop();
System.gc();
System.out.println("Used Memory:"
+ (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024*1024));
}
@Test(expected=IllegalStateException.class)
public void writeClosedSocket() throws IOException, InterruptedException, ExecutionException, TimeoutException {
final TCPClient client = SE.createTCPClient("localhost", port);
client.connect().get(5000, TimeUnit.MILLISECONDS);
client.close();
client.write(SMALL_TEXT_BUFFER.duplicate());
}
@Test
public void setClientOptions() throws IOException, InterruptedException {
final TCPClient client = SE.createTCPClient("localhost", port);
assertTrue(client.clientOptions().setTcpNoDelay(true));
assertTrue(client.clientOptions().getTcpNoDelay());
assertTrue(client.clientOptions().setTcpNoDelay(false));
assertFalse(client.clientOptions().getTcpNoDelay());
assertFalse(client.clientOptions().setSocketSendBuffer(0));
assertTrue(client.clientOptions().setSocketSendBuffer(16384));
assertEquals(16384, client.clientOptions().getSocketSendBuffer());
assertFalse(client.clientOptions().setSocketRecvBuffer(0));
assertTrue(client.clientOptions().setSocketRecvBuffer(16384));
assertEquals(16384, client.clientOptions().getSocketRecvBuffer());
assertFalse(client.clientOptions().setUdpFrameSize(1000));
assertEquals(-1, client.clientOptions().getUdpFrameSize());
assertFalse(client.isEncrypted());
if(!OS.contains("win")) {
assertFalse(client.clientOptions().setSocketSendBuffer(1));
assertFalse(client.clientOptions().setSocketRecvBuffer(1));
}
client.close();
Thread.sleep(100);
assertEquals(-1, client.clientOptions().getSocketRecvBuffer());
assertEquals(-1, client.clientOptions().getSocketSendBuffer());
assertFalse(client.clientOptions().setSocketSendBuffer(16384));
assertFalse(client.clientOptions().setSocketRecvBuffer(16384));
assertFalse(client.clientOptions().setTcpNoDelay(true));
assertFalse(client.clientOptions().getTcpNoDelay());
server.close();
}
@Test
public void simpleWriteTest() throws IOException, InterruptedException {
final TCPClient client = SE.createTCPClient("localhost", port);
final FakeTCPServerClient clientFC = new FakeTCPServerClient();
clientFC.addTCPClient(client);
client.connect();
new TestCondition(){
@Override
public boolean get() {
return serverFC.getNumberOfClients() == 1;
}
}.blockTillTrue(5000);
final TCPClient sclient = serverFC.getClientAt(0);
client.write(SMALL_TEXT_BUFFER.duplicate());
//System.out.println("1");
new TestCondition(){
@Override
public boolean get() {
return serverFC.getClientsBuffer(sclient).remaining() == SMALL_TEXT_BUFFER.remaining();
}
}.blockTillTrue(5000);
sclient.write(SMALL_TEXT_BUFFER.duplicate());
new TestCondition(){
@Override
public boolean get() {
boolean test = false;
try {
test = clientFC.getClientsBuffer(client).remaining() == SMALL_TEXT_BUFFER.remaining();
} catch(Exception e) {
}
return test;
}
}.blockTillTrue(1000);
client.close();
SE.setClientOperations(sclient);
new TestCondition(){
@Override
public boolean get() {
System.out.println(sclient.isClosed()+":"+client.isClosed());
SE.setClientOperations(client);
return sclient.isClosed() && client.isClosed();
}
}.blockTillTrue(10000, 100);
server.close();
}
@Test
public void simpleWriteTestNative() throws IOException, InterruptedException {
final TCPClient client = SE.createTCPClient("localhost", port);
client.clientOptions().setNativeBuffers(true);
final FakeTCPServerClient clientFC = new FakeTCPServerClient();
clientFC.addTCPClient(client);
client.connect();
new TestCondition(){
@Override
public boolean get() {
return serverFC.getNumberOfClients() == 1;
}
}.blockTillTrue(5000);
final TCPClient sclient = serverFC.getClientAt(0);
sclient.clientOptions().setNativeBuffers(true);
client.write(SMALL_TEXT_BUFFER.duplicate());
//System.out.println("1");
new TestCondition(){
@Override
public boolean get() {
return serverFC.getClientsBuffer(sclient).remaining() == SMALL_TEXT_BUFFER.remaining();
}
}.blockTillTrue(5000);
sclient.write(SMALL_TEXT_BUFFER.duplicate());
new TestCondition(){
@Override
public boolean get() {
boolean test = false;
try {
test =clientFC.getClientsBuffer(client).remaining() == SMALL_TEXT_BUFFER.remaining();
} catch(Exception e) {
}
return test;
}
}.blockTillTrue(1000);
client.close();
new TestCondition(){
@Override
public boolean get() {
return sclient.isClosed() && client.isClosed();
}
}.blockTillTrue(5000);
server.close();
}
@Test
public void serverCreate1() throws IOException {
server.close();
ServerSocketChannel socket = ServerSocketChannel.open();
socket.socket().bind(new InetSocketAddress("localhost", port), 100);
server = SE.createTCPServer(socket);
serverFC = new FakeTCPServerClient();
server.setClientAcceptor(serverFC);
server.start();
TCPClient client = SE.createTCPClient("localhost", port);
client.connect();
new TestCondition(){
@Override
public boolean get() {
return serverFC.getNumberOfClients() == 1;
}
}.blockTillTrue(5000, 100);
client.close();
server.close();
}
@Test
public void clientBlockingWriter() throws Exception {
final ByteBuffer bb = ByteBuffer.wrap("TEST111".getBytes());
final TCPClient client = SE.createTCPClient("localhost", port);
client.setMaxBufferSize(2);
serverFC.addTCPClient(client);
new TestCondition(){
@Override
public boolean get() {
return serverFC.getNumberOfClients() == 2;
}
}.blockTillTrue(5000);
TCPClient c2 = serverFC.getClientAt(1);
c2.setMaxBufferSize(2);
ArrayList<ListenableFuture<?>> lfl = new ArrayList<ListenableFuture<?>>();
for(int i=0; i<100; i++) {
lfl.add(c2.write(bb.duplicate()));
}
FutureUtils.makeCompleteFuture(lfl).get(5000, TimeUnit.MILLISECONDS);
System.out.println(client.canRead());
new TestCondition(){
@Override
public boolean get() {
System.out.println(client.canRead()+":"+serverFC.getClientsBuffer(client).remaining());
return serverFC.getClientsBuffer(client).remaining() == bb.remaining()*100;
}
}.blockTillTrue(5000, 1000);
c2.close();
new TestCondition(){
@Override
public boolean get() {
return serverFC.getNumberOfClients() == 0;
}
}.blockTillTrue(5000);
server.close();
}
@Test
public void clientRemoveReader() throws IOException, InterruptedException {
String text = "test";
StringBuilder sb = new StringBuilder();
for(int i=0; i<10; i++) {
sb.append(text);
}
System.out.println("1");
ByteBuffer bb = ByteBuffer.wrap(text.toString().getBytes());
final TCPClient client = SE.createTCPClient("localhost", port);
client.setMaxBufferSize(2);
client.setReader(new Reader() {
@Override
public void onRead(Client client) {
}});
System.out.println("2");
client.connect();
System.out.println("3");
new TestCondition(){
@Override
public boolean get() {
return serverFC.getNumberOfClients() == 1;
}
}.blockTillTrue(5000, 100);
System.out.println("4");
final TCPClient c2 = serverFC.getClientAt(0);
c2.setMaxBufferSize(60000);
System.out.println("5");
c2.write(bb.duplicate());
System.out.println("6");
new TestCondition() {
@Override
public boolean get() {
return ! client.canRead();
}
}.blockTillTrue(5000, 100);
System.out.println("7");
MergedByteBuffers readBB = client.getRead();
while(readBB.remaining() > 0) {
readBB = client.getRead();
}
System.out.println("8");
server.close();
}
@Test(expected=ClosedChannelException.class)
public void clientBadSocket1() throws IOException, InterruptedException {
SocketChannel cs = SocketChannel.open(new InetSocketAddress("localhost", port));
cs.close();
TCPClient client = SE.createTCPClient(cs);
server.close();
client.close();
}
@Test
public void clientAddSocket() throws IOException, InterruptedException {
SocketChannel cs = SocketChannel.open(new InetSocketAddress("localhost", port));
cs.configureBlocking(true);
TCPClient client = SE.createTCPClient(cs);
server.close();
client.close();
}
@Test
public void clientDoubleAdd() throws IOException, InterruptedException, ExecutionException {
SocketChannel cs = SocketChannel.open(new InetSocketAddress("localhost", port));
cs.configureBlocking(true);
TCPClient client = SE.createTCPClient(cs);
client.connect();
SE.setClientOperations(client);
SE.setClientOperations(client);
SE.setClientOperations(client);
SE.setClientOperations(client);
new TestCondition(){
@Override
public boolean get() {
System.out.println(SE.getClientCount());
return SE.getClientCount() == 2;
}
}.blockTillTrue(5000, 100);
client.close();
server.close();
}
@Test//(expected=IllegalStateException.class)
public void clientAddToStopedSE() throws IOException, InterruptedException {
SocketChannel cs = SocketChannel.open(new InetSocketAddress("localhost", port));
cs.configureBlocking(true);
TCPClient client = SE.createTCPClient(cs);
new TestCondition(){
@Override
public boolean get() {
return SE.getClientCount() == 2;
}
}.blockTillTrue(5000, 100);
//SE.addClient(client);
SE.stop();
SE.setClientOperations(client);
}
@Test
public void clientAddClosed() throws IOException, InterruptedException {
SocketChannel cs = SocketChannel.open(new InetSocketAddress("localhost", port));
cs.configureBlocking(true);
TCPClient client = SE.createTCPClient(cs);
new TestCondition(){
@Override
public boolean get() {
return SE.getClientCount() == 2;
}
}.blockTillTrue(5000);
client.close();
new TestCondition(){
@Override
public boolean get() {
return SE.getClientCount() == 0;
}
}.blockTillTrue(5000);
assertEquals(0, SE.getClientCount());
SE.setClientOperations(client);
SE.setClientOperations(client);
assertEquals(0, SE.getClientCount());
client.close();
server.close();
}
@Test
public void clientStartingWrite() throws IOException, InterruptedException {
TCPClient client = SE.createTCPClient("localhost", port);
final FakeTCPServerClient clientFC = new FakeTCPServerClient();
client.write(SMALL_TEXT_BUFFER.duplicate());
clientFC.addTCPClient(client);
client.connect();
new TestCondition(){
@Override
public boolean get() {
return serverFC.getNumberOfClients() == 1;
}
}.blockTillTrue(5000);
final TCPClient cf = serverFC.getClientAt(0);
new TestCondition(){
@Override
public boolean get() {
return serverFC.getClientsBuffer(cf).remaining() > 0 ;
}
}.blockTillTrue(5000);
assertEquals(serverFC.getClientsBuffer(cf).remaining(), SMALL_TEXT_BUFFER.remaining());
assertEquals(serverFC.getClientsBuffer(cf).getAsString(serverFC.getClientsBuffer(cf).remaining()), SMALL_TEXT);
}
@Test
public void clientLateReadStart() throws IOException, InterruptedException {
final TCPClient client = SE.createTCPClient("localhost", port);
for(int i=0; i<50000; i++) {
client.write(SMALL_TEXT_BUFFER.duplicate());
}
final FakeTCPServerClient clientFC = new FakeTCPServerClient();
clientFC.addTCPClient(client);
client.connect();
new TestCondition(){
@Override
public boolean get() {
return serverFC.getNumberOfClients() == 1;
}
}.blockTillTrue(5000);
final TCPClient c2 = serverFC.getClientAt(0);
client.connect();
c2.connect();
new TestCondition(){
@Override
public boolean get() {
//System.out.println(client.getWriteBufferSize());
return serverFC.getClientsBuffer(c2).remaining() == SMALL_TEXT_BUFFER.remaining()*50000 ;
}
}.blockTillTrue(10000);
}
@Test
public void bigWrite() throws IOException, InterruptedException {
final TCPClient client = SE.createTCPClient("localhost", port);
final FakeTCPServerClient clientFC = new FakeTCPServerClient();
client.write(LARGE_TEXT_BUFFER.duplicate());
clientFC.addTCPClient(client);
client.write(LARGE_TEXT_BUFFER.duplicate());
client.write(LARGE_TEXT_BUFFER.duplicate());
client.write(LARGE_TEXT_BUFFER.duplicate());
client.connect();
new TestCondition(){
@Override
public boolean get() {
return serverFC.getNumberOfClients() == 1;
}
}.blockTillTrue(5000);
final TCPClient cf = serverFC.getClientAt(0);
new TestCondition(){
@Override
public boolean get() {
//System.out.println(serverFC.map.get(cf).remaining()+":"+(LARGE_TEXT_BUFFER.remaining()*4));
return serverFC.getClientsBuffer(cf).remaining() == LARGE_TEXT_BUFFER.remaining()*4 ;
}
}.blockTillTrue(5000);
assertEquals(serverFC.getClientsBuffer(cf).remaining(), LARGE_TEXT_BUFFER.remaining()*4);
assertEquals(serverFC.getClientsBuffer(cf).getAsString(LARGE_TEXT_BUFFER.remaining()), LARGE_TEXT);
assertEquals(serverFC.getClientsBuffer(cf).getAsString(LARGE_TEXT_BUFFER.remaining()), LARGE_TEXT);
assertEquals(serverFC.getClientsBuffer(cf).getAsString(LARGE_TEXT_BUFFER.remaining()), LARGE_TEXT);
assertEquals(serverFC.getClientsBuffer(cf).getAsString(LARGE_TEXT_BUFFER.remaining()), LARGE_TEXT);
System.out.println(client.getStats().getTotalRead());
System.out.println(client.getStats().getReadRate());
System.out.println(client.getStats().getTotalWrite());
System.out.println(client.getStats().getWriteRate());
System.out.println("-----");
System.out.println(cf.getStats().getTotalRead());
System.out.println(cf.getStats().getReadRate());
System.out.println(cf.getStats().getTotalRead());
System.out.println(cf.getStats().getReadRate());
System.out.println(cf.getStats().getTotalWrite());
System.out.println(cf.getStats().getWriteRate());
}
@Test(expected=ExecutionException.class)
public void tcpBadAddress() throws IOException, InterruptedException, ExecutionException {
TCPClient client = SE.createTCPClient("2.0.0.256", port);
client.setConnectionTimeout(1000);
client.connect().get();
}
@Test
public void tcpTimeout() throws Throwable {
TCPClient client = SE.createTCPClient("2.0.0.2", port);
client.setConnectionTimeout(1);
assertTrue(!client.hasConnectionTimedOut());
ListenableFuture<?> lf = client.connect();
Thread.sleep(10);
assertTrue(client.hasConnectionTimedOut());
System.out.println(lf.isCancelled());
System.out.println(lf.isDone());
while(!lf.isCancelled() || !lf.isDone()) {
Thread.sleep(1);
}
System.out.println(lf.isCancelled());
System.out.println(lf.isDone());
//assertTrue(lf.isCancelled());
}
@Test(expected=ConnectException.class)
public void tcpConnectionRefused() throws Throwable {
server.close();
TCPClient client = SE.createTCPClient("localhost", port);
assertTrue(!client.hasConnectionTimedOut());
//final FakeTCPServerClient clientFC = new FakeTCPServerClient(SE);
try {
client.connect().get(5000, TimeUnit.MILLISECONDS);
fail();
} catch(ExecutionException e) {
assertTrue(!client.hasConnectionTimedOut());
assertEquals(0, SE.getClientCount());
throw e.getCause();
}
}
@Test
public void closedServerStartTest() throws Exception {
server.close();
SE.startListening(server);
SocketExecuter SE2 = new ThreadedSocketExecuter();
SE2.start();
TCPServer server2 = SE2.createTCPServer("localhost", port);
SE.startListening(server2);
server2.close();
SE2.stopIfRunning();
}
@Test
public void writerReaderBlockTest() throws Exception {
TCPClient tc = SE.createTCPClient("localhost", port);
tc.connect().get(5000, TimeUnit.MILLISECONDS);
new TestCondition() {
@Override
public boolean get() {
return serverFC.getNumberOfClients() == 1;
}
}.blockTillTrue(5000);
TCPClient sc = serverFC.getClientAt(0);
while(tc.canRead()) {
sc.write(LARGE_TEXT_BUFFER.duplicate());
Thread.sleep(10);
}
sc.setReader(null);
while(sc.canRead()) {
tc.write(LARGE_TEXT_BUFFER.duplicate());
Thread.sleep(10);
}
assertFalse(sc.canRead());
assertFalse(tc.canRead());
assertTrue(sc.getReadBufferSize() >= sc.getMaxBufferSize());
assertTrue(tc.getReadBufferSize() >= tc.getMaxBufferSize());
SE.setClientOperations(sc);
SE.setClientOperations(tc);
assertFalse(sc.canRead());
assertFalse(tc.canRead());
assertTrue(sc.getReadBufferSize() >= sc.getMaxBufferSize());
assertTrue(tc.getReadBufferSize() >= tc.getMaxBufferSize());
}
@Test
public void manyClientsMemoryTest() throws Exception {
ArrayList<ListenableFuture<?>> lfl = new ArrayList<ListenableFuture<?>>();
for(int i=0; i<100; i++) {
TCPClient tc = SE.createTCPClient("127.0.0.1", port);
serverFC.addTCPClient(tc);
lfl.add(tc.connect());
}
FutureUtils.makeCompleteFuture(lfl).get(5000, TimeUnit.MILLISECONDS);
new TestCondition(){
@Override
public boolean get() {
return 200 == SE.getClientCount() ;
}
}.blockTillTrue(5000);
assertEquals(200, SE.getClientCount());
for(TCPClient tc: serverFC.getAllClients()) {
tc.write(SMALL_TEXT_BUFFER.duplicate());
}
System.gc();
System.out.println("Used Memory:"
+ (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024*1024));
for(TCPClient tc: serverFC.getAllClients()) {
MergedByteBuffers mbb = serverFC.getClientsBuffer(tc);
mbb.discard(mbb.remaining());
}
System.gc();
System.out.println("Used Memory:"
+ (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024*1024));
}
}