package com.javachat.server;
import com.javachat.shared.Command;
import com.javachat.shared.MessageHolder;
import junit.framework.Assert;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.*;
/**
* @author Dmitry Levykin
*/
public class ChatServerTest {
private static final int PORT = 3000;
private ChatServer chatServer;
private final String USER = "Test user";
ChatServer getChatServer() {
return chatServer;
}
@Before
public void init() throws IOException {
chatServer = new ChatServer();
chatServer.bind(PORT);
}
@After
public void stop() throws IOException {
chatServer.stop();
}
// Канал подключения
private SocketChannel connect() throws IOException {
SocketChannel channel = SocketChannel.open();
channel.connect(new InetSocketAddress("localhost", PORT));
sendMessage(channel, (Command.LOGIN.getText() + USER).getBytes(ChatServer.CHARSET_NAME));
readServerMessages(1);
writeAllServerBuffers();
readMessage(channel);
return channel;
}
// Отправка сообщения в канал
private void sendMessage(SocketChannel channel, byte[] messageBytes) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(messageBytes.length + 4);
buffer.putInt(messageBytes.length);
buffer.put(messageBytes);
buffer.flip();
channel.write(buffer);
}
// Чтение сообщения из канала
private String readMessage(SocketChannel channel) throws IOException {
return readMessages(channel, 1).get(0);
}
// Чтение сообщений из канала
private List<String> readMessages(SocketChannel channel, int count) throws IOException {
List<String> retList = new LinkedList<>();
MessageHolder holder = null;
ByteBuffer end = null;
ByteBuffer buffer = ByteBuffer.allocate(10);
while (count > 0) {
if (holder == null) {
holder = new MessageHolder(100, ChatServer.CHARSET_NAME);
}
if (end != null) {
buffer.put(end);
}
channel.read(buffer);
buffer.flip();
String message = holder.readFromBuffer(buffer);
if (message != null) {
retList.add(message);
holder = null;
count--;
}
if (buffer.hasRemaining()) {
end = ByteBuffer.allocate(buffer.remaining());
end.put(buffer);
end.flip();
}
buffer.flip();
}
return retList;
}
// Запуск сервера без клиентов. Сервер должен быть без активности.
@Test(timeout = 100)
public void startServerTest() throws IOException {
Assert.assertTrue(!chatServer.keyIteration());
}
// Заставляем сервер прочитать все входящие сообщения
private void readServerMessages(int count) throws IOException {
int countBefore = chatServer.getIncomeMessagesOrCommandsCount();
while (chatServer.getIncomeMessagesOrCommandsCount() < countBefore + count) {
chatServer.select();
chatServer.keyIteration();
}
}
// Заставляем сервер отослать все исходящие сообщения
private void writeAllServerBuffers() throws IOException {
do {
chatServer.select();
} while (chatServer.keyIteration());
}
// Отправка одного сообщения
@Test(timeout = 100)
public void sendOneMessagesTest() throws IOException {
chatServer.setBufferCapacity(10);
String message = "Hello!";
SocketChannel channel = connect();
sendMessage(channel, message.getBytes(ChatServer.CHARSET_NAME));
readServerMessages(1);
channel.close();
Assert.assertEquals(1, chatServer.getClientMessages().size());
Assert.assertEquals(message, chatServer.getClientMessages().get(0).getText());
}
// Отправка одного сообщения между двумя клиентами
@Test(timeout = 100)
public void sendOneMessagesC2CTest() throws IOException {
chatServer.setBufferCapacity(10);
String message1 = "Hello!";
SocketChannel channel1 = connect();
SocketChannel channel2 = connect();
sendMessage(channel1, message1.getBytes(ChatServer.CHARSET_NAME));
readServerMessages(1);
writeAllServerBuffers();
String message2 = readMessage(channel2);
channel1.close();
channel2.close();
Assert.assertEquals(ChatServer.getUserMessageString(USER, message1), message2);
}
// Отправка двух сообщений с буфером превосходящим их совокупный размер
@Test(timeout = 100)
public void sendTwoMessagesWithLargeBufferTest() throws IOException {
chatServer.setBufferCapacity(20);
String message1 = "Hello!";
String message2 = "Hi!";
SocketChannel channel = connect();
sendMessage(channel, message1.getBytes(ChatServer.CHARSET_NAME));
sendMessage(channel, message2.getBytes(ChatServer.CHARSET_NAME));
readServerMessages(2);
channel.close();
Assert.assertEquals(2, chatServer.getClientMessages().size());
Assert.assertEquals(message1, chatServer.getClientMessages().get(0).getText());
Assert.assertEquals(message2, chatServer.getClientMessages().get(1).getText());
}
// Отправка двух сообщений с ограниченным буфером
@Test(timeout = 100)
public void sendTwoWithSmallBufferTest() throws IOException {
chatServer.setBufferCapacity(10);
String message1 = "Hello!";
String message2 = "Hi!";
SocketChannel channel = connect();
sendMessage(channel, message1.getBytes(ChatServer.CHARSET_NAME));
sendMessage(channel, message2.getBytes(ChatServer.CHARSET_NAME));
readServerMessages(2);
channel.close();
Assert.assertEquals(2, chatServer.getClientMessages().size());
Assert.assertEquals(message1, chatServer.getClientMessages().get(0).getText());
Assert.assertEquals(message2, chatServer.getClientMessages().get(1).getText());
}
// Большое количество сообщений от одного клиента
@Test(timeout = 300)
public void sendMessagesTest() throws IOException {
chatServer.setBufferCapacity(20);
SocketChannel channel = connect();
// Accept
chatServer.select();
chatServer.keyIteration();
int sendCount = 1000;
List<String> sendList = new ArrayList<>(sendCount);
for (int i = 0; i < sendCount; i++) {
String message = "Message " + i;
sendList.add(message);
sendMessage(channel, message.getBytes(ChatServer.CHARSET_NAME));
readServerMessages(1);
}
channel.close();
List<ChatMessage> receiveList = chatServer.getClientMessages();
Assert.assertEquals(sendCount, receiveList.size());
for (int i = 0; i < sendCount; i++) {
Assert.assertEquals(sendList.get(i), receiveList.get(i).getText());
}
}
// Одновременное подключение 100 пользователей. Каждый посылает по сообщению.
@Test(timeout = 1000)
public void send100Messages() throws IOException {
chatServer.setBufferCapacity(30);
int count = 100;
List<SocketChannel> channelList = new ArrayList<>(count);
Map<SocketChannel, List<String>> messagesMap = new HashMap<>();
// Подключение и авторизация
for (int i = 0; i < count; i++) {
channelList.add(connect());
messagesMap.put(channelList.get(i), new ArrayList<String>(count - 1));
}
// Отправка
for (int i = 0; i < count; i++) {
String message = "Message from " + i;
sendMessage(channelList.get(i), message.getBytes(ChatServer.CHARSET_NAME));
readServerMessages(1);
}
writeAllServerBuffers();
// Получение сообщений - самая долгая операция
Assert.assertEquals(count, chatServer.getClientMessages().size());
for (SocketChannel channel : channelList) {
List<String> messageList = readMessages(channel, count - 1);
Assert.assertEquals(count - 1, messageList.size());
channel.close();
}
}
}