package com.jenjinstudios.core;
import com.jenjinstudios.core.io.*;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import static org.mockito.Mockito.*;
/**
* Test the {@code Connection} class.
*
* @author Caleb Brinkman
*/
@SuppressWarnings("OverlyCoupledClass")
public class ConnectionTest
{
private static final MessageRegistry MESSAGE_REGISTRY = MessageRegistry.getInstance();
private static final int INVALID_MESSAGE_ID = -255;
private static final long REQUEST_TIME_SPOOF = 123456789L;
/**
* Test the {@code processMessage} method.
*
* @throws Exception If there's an exception.
*/
@Test
public void testProcessMessage() throws Exception {
// Spoof an invalid message
DataInputStreamMock dataInputStreamMock = new DataInputStreamMock();
dataInputStreamMock.mockReadShort((short) INVALID_MESSAGE_ID);
dataInputStreamMock.mockReadShort((short) -1);
dataInputStreamMock.mockReadBoolean(false);
dataInputStreamMock.mockReadUtf("FooBar");
dataInputStreamMock.mockReadShort((short) -1);
InputStream in = dataInputStreamMock.getIn();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
MessageInputStream messageInputStream = new MessageInputStream(in);
MessageOutputStream messageOutputStream = new MessageOutputStream(bos);
MessageIO messageIO = new MessageIO(messageInputStream, messageOutputStream);
Connection connection = new Connection(messageIO);
connection.start();
Thread.sleep(100);
connection.getExecutableMessageQueue().runQueuedExecutableMessages();
try
{
connection.getMessageIO().writeAllMessages();
} catch (IOException e)
{
connection.shutdown();
}
connection.shutdown();
// The connection should execute the InvalidExecutableMessage,
byte[] bytes = bos.toByteArray();
MessageInputStream mis = new MessageInputStream(new ByteArrayInputStream(bytes));
Message msg = mis.readMessage();
Assert.assertEquals(msg.getArgument("messageName"), "Unknown", "Argument does not match");
}
/**
* Test the {@code shutdown} method.
*
* @throws Exception If there's an exception.
*/
@Test(expectedExceptions = MessageQueueException.class)
public void testShutDown() throws Exception {
DataInputStreamMock dataInputStreamMock = new DataInputStreamMock();
InputStream in = dataInputStreamMock.getIn();
dataInputStreamMock.mockReadShort((short) INVALID_MESSAGE_ID);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
MessageInputStream messageInputStream = new MessageInputStream(in);
MessageOutputStream messageOutputStream = new MessageOutputStream(bos);
MessageIO messageIO = new MessageIO(messageInputStream, messageOutputStream);
Connection connection = new Connection(messageIO);
connection.shutdown();
Message msg = MESSAGE_REGISTRY.createMessage("InvalidMessage");
msg.setArgument("messageName", "FooBar");
msg.setArgument("messageID", (short) INVALID_MESSAGE_ID);
connection.getMessageIO().queueOutgoingMessage(msg);
try
{
connection.getMessageIO().writeAllMessages();
} catch (IOException e)
{
connection.shutdown();
}
}
/**
* Test the ping request functionality.
*
* @throws Exception If there's an exception.
*/
@Test
public void testPingRequest() throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
MessageInputStream messageInputStream = mock(MessageInputStream.class);
MessageOutputStream messageOutputStream = new MessageOutputStream(bos);
Message pingRequest = MESSAGE_REGISTRY.createMessage("PingRequest");
pingRequest.setArgument("requestTimeMillis", REQUEST_TIME_SPOOF);
when(messageInputStream.readMessage()).thenReturn(pingRequest).thenReturn(MESSAGE_REGISTRY.createMessage
("BlankMessage"));
MessageIO messageIO = new MessageIO(messageInputStream, messageOutputStream);
Connection connection = new Connection(messageIO);
connection.start();
Thread.sleep(100);
connection.getExecutableMessageQueue().runQueuedExecutableMessages();
try
{
connection.getMessageIO().writeAllMessages();
} catch (IOException e)
{
connection.shutdown();
}
connection.shutdown();
// The connection should execute the InvalidExecutableMessage,
byte[] bytes = bos.toByteArray();
MessageInputStream mis = new MessageInputStream(new ByteArrayInputStream(bytes));
Message msg = mis.readMessage();
Assert.assertEquals(msg.name, "PingResponse", "Message not PingResponse");
}
/**
* Test the ping response functionality.
*
* @throws Exception If there's an exception.
*/
@Test
public void testPingResponse() throws Exception {
// Spoof an invalid message
DataInputStreamMock dataInputStreamMock = new DataInputStreamMock();
dataInputStreamMock.mockReadShort((short) 3);
dataInputStreamMock.mockReadInt(1);
dataInputStreamMock.mockReadByte((byte) 0);
dataInputStreamMock.mockReadShort((short) 2);
dataInputStreamMock.mockReadLong(System.currentTimeMillis());
InputStream in = dataInputStreamMock.getIn();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
MessageInputStream messageInputStream = new MessageInputStream(in);
MessageOutputStream messageOutputStream = new MessageOutputStream(bos);
MessageIO messageIO = new MessageIO(messageInputStream, messageOutputStream);
Connection connection = new Connection(messageIO);
// Create and run the connection. Normally, we would use connection.start() to spawn a new thread
// but for testing purposes we want the connection to run in the current thread.
connection.start();
Thread.sleep(100);
// Again, normally an implementation would schedule this, but that's excessive for testing purposes
connection.getExecutableMessageQueue().runQueuedExecutableMessages();
try
{
connection.getMessageIO().writeAllMessages();
} catch (IOException e)
{
connection.shutdown();
}
connection.shutdown();
// Ping time should be extremely close to 0, but taking into account wonkiness with tests, I'll allow
// up to 1000
Assert.assertEquals(connection.getPingTracker().getAveragePingTime(), 0, 1000, "Ping response too high\n" +
"this may be a one off, try running again before digging too deeply.");
}
}