package games.strategy.net;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.io.Serializable;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import games.strategy.debug.ClientLogger;
import games.strategy.test.TestUtil;
import games.strategy.util.ThreadUtil;
public class MessengerTest {
private static int SERVER_PORT = -1;
private IServerMessenger serverMessenger;
private IMessenger client1Messenger;
private IMessenger client2Messenger;
private final MessageListener serverMessageListener = new MessageListener();
private final MessageListener client1MessageListener = new MessageListener();
private final MessageListener client2MessageListener = new MessageListener();
@Before
public void setUp() throws IOException {
SERVER_PORT = TestUtil.getUniquePort();
serverMessenger = new ServerMessenger("Server", SERVER_PORT);
serverMessenger.setAcceptNewConnections(true);
serverMessenger.addMessageListener(serverMessageListener);
final String mac = MacFinder.getHashedMacAddress();
client1Messenger = new ClientMessenger("localhost", SERVER_PORT, "client1", mac);
client1Messenger.addMessageListener(client1MessageListener);
client2Messenger = new ClientMessenger("localhost", SERVER_PORT, "client2", mac);
client2Messenger.addMessageListener(client2MessageListener);
assertEquals(client1Messenger.getServerNode(), serverMessenger.getLocalNode());
assertEquals(client2Messenger.getServerNode(), serverMessenger.getLocalNode());
assertEquals(serverMessenger.getServerNode(), serverMessenger.getLocalNode());
for (int i = 0; i < 100; i++) {
if (serverMessenger.getNodes().size() != 3) {
ThreadUtil.sleep(1);
} else {
break;
}
}
assertEquals(serverMessenger.getNodes().size(), 3);
}
@After
public void tearDown() {
try {
if (serverMessenger != null) {
serverMessenger.shutDown();
}
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
try {
if (client1Messenger != null) {
client1Messenger.shutDown();
}
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
try {
if (client2Messenger != null) {
client2Messenger.shutDown();
}
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
}
@Test
public void testServerSend() {
final String message = "Hello";
serverMessenger.send(message, client1Messenger.getLocalNode());
assertEquals(client1MessageListener.getLastMessage(), message);
assertEquals(client1MessageListener.getLastSender(), serverMessenger.getLocalNode());
assertEquals(client2MessageListener.getMessageCount(), 0);
}
@Test
public void testServerSendToClient2() throws Exception {
final String message = "Hello";
serverMessenger.send(message, client2Messenger.getLocalNode());
assertEquals(client2MessageListener.getLastMessage(), message);
assertEquals(client2MessageListener.getLastSender(), serverMessenger.getLocalNode());
assertEquals(client1MessageListener.getMessageCount(), 0);
}
@Test
public void testClientSendToServer() {
final String message = "Hello";
client1Messenger.send(message, serverMessenger.getLocalNode());
assertEquals(serverMessageListener.getLastMessage(), message);
assertEquals(serverMessageListener.getLastSender(), client1Messenger.getLocalNode());
assertEquals(client1MessageListener.getMessageCount(), 0);
assertEquals(client2MessageListener.getMessageCount(), 0);
}
@Test
public void testClientSendToClient() {
final String message = "Hello";
client1Messenger.send(message, client2Messenger.getLocalNode());
assertEquals(client2MessageListener.getLastMessage(), message);
assertEquals(client2MessageListener.getLastSender(), client1Messenger.getLocalNode());
assertEquals(client1MessageListener.getMessageCount(), 0);
assertEquals(serverMessageListener.getMessageCount(), 0);
}
@Test
public void testClientSendToClientLargeMessage() {
final int count = 1 * 1000 * 1000;
final StringBuilder builder = new StringBuilder(count);
for (int i = 0; i < count; i++) {
builder.append('a');
}
final String message = builder.toString();
client1Messenger.send(message, client2Messenger.getLocalNode());
assertEquals(client2MessageListener.getLastMessage(), message);
assertEquals(client2MessageListener.getLastSender(), client1Messenger.getLocalNode());
assertEquals(client1MessageListener.getMessageCount(), 0);
assertEquals(serverMessageListener.getMessageCount(), 0);
}
@Test
public void testServerBroadcast() {
final String message = "Hello";
serverMessenger.broadcast(message);
assertEquals(client1MessageListener.getLastMessage(), message);
assertEquals(client1MessageListener.getLastSender(), serverMessenger.getLocalNode());
assertEquals(client2MessageListener.getLastMessage(), message);
assertEquals(client2MessageListener.getLastSender(), serverMessenger.getLocalNode());
assertEquals(serverMessageListener.getMessageCount(), 0);
}
@Test
public void testClientBroadcast() {
final String message = "Hello";
client1Messenger.broadcast(message);
assertEquals(client2MessageListener.getLastMessage(), message);
assertEquals(client2MessageListener.getLastSender(), client1Messenger.getLocalNode());
assertEquals(serverMessageListener.getLastMessage(), message);
assertEquals(serverMessageListener.getLastSender(), client1Messenger.getLocalNode());
assertEquals(client1MessageListener.getMessageCount(), 0);
}
@Test
public void testMultipleServer() {
for (int i = 0; i < 100; i++) {
serverMessenger.send(i, client1Messenger.getLocalNode());
}
for (int i = 0; i < 100; i++) {
client1MessageListener.clearLastMessage();
}
}
@Test
public void testMultipleClientToClient() {
for (int i = 0; i < 100; i++) {
client1Messenger.send(i, client2Messenger.getLocalNode());
}
for (int i = 0; i < 100; i++) {
client2MessageListener.clearLastMessage();
}
}
@Test
public void testMultipleMessages() throws Exception {
final Thread t1 = new Thread(new MultipleMessageSender(serverMessenger));
final Thread t2 = new Thread(new MultipleMessageSender(client1Messenger));
final Thread t3 = new Thread(new MultipleMessageSender(client2Messenger));
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
for (int i = 0; i < 200; i++) {
client1MessageListener.clearLastMessage();
}
for (int i = 0; i < 200; i++) {
client2MessageListener.clearLastMessage();
}
for (int i = 0; i < 200; i++) {
serverMessageListener.clearLastMessage();
}
}
@Test
public void testCorrectNodeCountInRemove() {
// when we receive the notification that a
// connection has been lost, the node list
// should reflect that change
for (int i = 0; i < 100; i++) {
if (serverMessenger.getNodes().size() == 3) {
break;
}
ThreadUtil.sleep(10);
}
final AtomicInteger m_serverCount = new AtomicInteger(3);
serverMessenger.addConnectionChangeListener(new IConnectionChangeListener() {
@Override
public void connectionRemoved(final INode to) {
m_serverCount.decrementAndGet();
}
@Override
public void connectionAdded(final INode to) {
fail();
}
});
client1Messenger.shutDown();
for (int i = 0; i < 100; i++) {
if (serverMessenger.getNodes().size() == 2) {
ThreadUtil.sleep(10);
break;
}
ThreadUtil.sleep(10);
}
assertEquals(2, m_serverCount.get());
}
@Test
public void testDisconnect() {
for (int i = 0; i < 100; i++) {
if (serverMessenger.getNodes().size() == 3) {
break;
}
ThreadUtil.sleep(10);
}
assertEquals(3, serverMessenger.getNodes().size());
client1Messenger.shutDown();
client2Messenger.shutDown();
for (int i = 0; i < 100; i++) {
if (serverMessenger.getNodes().size() == 1) {
ThreadUtil.sleep(10);
break;
}
ThreadUtil.sleep(1);
}
assertEquals(serverMessenger.getNodes().size(), 1);
}
@Test
public void testClose() {
final AtomicBoolean closed = new AtomicBoolean(false);
client1Messenger.addErrorListener(new IMessengerErrorListener() {
@Override
public void messengerInvalid(final IMessenger messenger, final Exception reason) {
closed.set(true);
}
});
serverMessenger.removeConnection(client1Messenger.getLocalNode());
int waitCount = 0;
while (!closed.get() && waitCount < 10) {
ThreadUtil.sleep(40);
waitCount++;
}
assert (closed.get());
}
@Test
public void testManyClients() throws UnknownHostException, CouldNotLogInException, IOException {
final int count = 5;
final List<ClientMessenger> clients = new ArrayList<>();
final List<MessageListener> listeners = new ArrayList<>();
for (int i = 0; i < count; i++) {
final String name = "newClient" + i;
final String mac = MacFinder.getHashedMacAddress();
final ClientMessenger messenger = new ClientMessenger("localhost", SERVER_PORT, name, mac);
final MessageListener listener = new MessageListener();
messenger.addMessageListener(listener);
clients.add(messenger);
listeners.add(listener);
}
serverMessenger.broadcast("TEST");
for (final MessageListener listener : listeners) {
assertEquals("TEST", listener.getLastMessage());
}
for (int i = 0; i < count; i++) {
clients.get(i).shutDown();
}
}
private static class MessageListener implements IMessageListener {
private final List<Serializable> messages = new ArrayList<>();
private final ArrayList<INode> senders = new ArrayList<>();
private final Object lock = new Object();
@Override
public void messageReceived(final Serializable msg, final INode from) {
synchronized (lock) {
messages.add(msg);
senders.add(from);
lock.notifyAll();
}
}
public void clearLastMessage() {
synchronized (lock) {
if (messages.isEmpty()) {
waitForMessage();
}
messages.remove(0);
senders.remove(0);
}
}
public Object getLastMessage() {
synchronized (lock) {
if (messages.isEmpty()) {
waitForMessage();
}
assertFalse(messages.isEmpty());
return messages.get(0);
}
}
public INode getLastSender() {
synchronized (lock) {
if (messages.isEmpty()) {
waitForMessage();
}
return senders.get(0);
}
}
private void waitForMessage() {
try {
lock.wait(1500);
} catch (final InterruptedException e) {
fail("unexpected exception: " + e.getMessage());
}
}
public int getMessageCount() {
synchronized (lock) {
return messages.size();
}
}
}
private static class MultipleMessageSender implements Runnable {
IMessenger messenger;
public MultipleMessageSender(final IMessenger messenger) {
this.messenger = messenger;
}
@Override
public void run() {
Thread.yield();
for (int i = 0; i < 100; i++) {
messenger.broadcast(i);
}
}
}
}