Server/Server/src/test/java/uulm/teamname/marvelous/server/MarvelousServerTest.java

199 lines
7.3 KiB
Java

package uulm.teamname.marvelous.server;
import org.java_websocket.WebSocket;
import org.junit.jupiter.api.*;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.tinylog.configuration.Configuration;
import uulm.teamname.marvelous.gamelibrary.json.JSON;
import uulm.teamname.marvelous.gamelibrary.messages.BasicMessage;
import uulm.teamname.marvelous.gamelibrary.messages.RoleEnum;
import uulm.teamname.marvelous.gamelibrary.messages.client.CharacterSelectionMessage;
import uulm.teamname.marvelous.gamelibrary.messages.client.HelloServerMessage;
import uulm.teamname.marvelous.gamelibrary.messages.client.PlayerReadyMessage;
import uulm.teamname.marvelous.gamelibrary.messages.server.*;
import uulm.teamname.marvelous.server.lobbymanager.LobbyManager;
import uulm.teamname.marvelous.server.netconnector.UserManager;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import static org.mockito.Mockito.*;
class MarvelousServerTest extends BaseGameLogicTest {
private static MockedStatic<Server> serverMock;
private static JSON json;
@BeforeAll
static void start() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Constructor<UserManager> um = UserManager.class.getDeclaredConstructor();
um.setAccessible(true);
um.newInstance();
Constructor<LobbyManager> lm = LobbyManager.class.getDeclaredConstructor();
lm.setAccessible(true);
lm.newInstance();
serverMock = Mockito.mockStatic(Server.class);
generate();
serverMock.when(Server::getMaxLobbies).thenReturn(10);
serverMock.when(Server::getPartyConfig).thenReturn(partyConfig);
serverMock.when(Server::getScenarioConfig).thenReturn(scenarioConfig);
serverMock.when(Server::getCharacterConfig).thenReturn(characterConfig);
json = new JSON(characterConfig);
Map<String, String> map = new HashMap<>();
Configuration.replace(map);
map.put("writer1", "console");
map.put("writer1.level", "trace");
map.put("writer1.format", "[{thread}] {level}: {message}");
Configuration.replace(map);
}
@Test
void main() {
UserManager m = UserManager.getInstance();
WebSocket p1 = mock(WebSocket.class);
WebSocket p2 = mock(WebSocket.class);
WebSocket s1 = mock(WebSocket.class);
WebSocket s2 = mock(WebSocket.class);
m.connectUser(p1);
ensureHandshake(m, p1, "Player 1", "1234", false);
m.connectUser(p2);
ensureHandshake(m, p2, "Player 2", "4321", false);
m.connectUser(s1);
ensureHandshake(m, s1, "Spectator 1", "3333", false);
m.connectUser(s2);
ensureHandshake(m, s2, "Spectator 2", "4444", false);
ensurePlayerReady(m, p1, true, RoleEnum.PLAYER);
ensurePlayerReady(m, p2, true, RoleEnum.PLAYER);
ensureSpectatorReady(m, s1, true, RoleEnum.SPECTATOR);
//these are broken right now because Server doesn't get mocked in lobby threads
/*
ensureCharacterSelection(m, p1, false);
ensureCharacterSelection(m, p2, true);
ensureReceived(p1, new GameStructureMessage());
ensureReceived(p2, new GameStructureMessage());
ensureReceived(s1, new GameStructureMessage());
*/
}
private void ensureHandshake(UserManager m, WebSocket c, String name, String deviceID, boolean runningGame) {
HelloServerMessage message = new HelloServerMessage();
message.name = name;
message.deviceID = deviceID;
HelloClientMessage response = new HelloClientMessage();
response.runningGame = runningGame;
ensureResponse(m, c, message, response);
}
private void ensurePlayerReady(UserManager m, WebSocket c, boolean startGame, RoleEnum role) {
PlayerReadyMessage message = new PlayerReadyMessage();
message.startGame = startGame;
message.role = role;
GameAssignmentMessage response = new GameAssignmentMessage();
//properties are left null because we can't test their content (they are random)
ensureResponse(m, c, message, response);
}
private void ensureSpectatorReady(UserManager m, WebSocket c, boolean startGame, RoleEnum role) {
PlayerReadyMessage message = new PlayerReadyMessage();
message.startGame = startGame;
message.role = role;
GeneralAssignmentMessage response = new GeneralAssignmentMessage();
//properties are left null because we can't test their content (they are random)
ensureResponse(m, c, message, response);
}
private void ensureCharacterSelection(UserManager m, WebSocket c, boolean selectionComplete) {
CharacterSelectionMessage message = new CharacterSelectionMessage();
message.characters = new Boolean[12];
for(int i = 0; i < 6; i++) {
message.characters[i] = true;
}
for(int i = 6; i < 12; i++) {
message.characters[i] = false;
}
ConfirmSelectionMessage response = new ConfirmSelectionMessage();
response.selectionComplete = selectionComplete;
ensureResponse(m, c, message, response);
}
/** Ensures that the given socket received the given response in response to the given message. */
private void ensureResponse(UserManager m, WebSocket c, BasicMessage message, BasicMessage response) {
Optional<String> in = json.stringify(message);
if(in.isPresent()) {
m.messageReceived(c, in.get());
verify(c).send((String)argThat(
(out)->verifyResponse((String)out, response)
));
clearInvocations(c);
}else {
throw new IllegalArgumentException("[TEST] Message in test call could not be serialized!");
}
}
/** Ensures that the given socket received the given response. */
private void ensureReceived(WebSocket c, BasicMessage response) {
verify(c).send((String)argThat(
(out)->verifyResponse((String)out, response)
));
}
/**
* Verifies a response message and requires all non-null fields of the expected message
* to equal the respective values in the actual received message.
*/
private <T extends BasicMessage> boolean verifyResponse(String actual, T expected) {
Optional<BasicMessage> in = json.parse(actual);
if(in.isPresent()) {
T message = (T) in.get();
for(Field field: expected.getClass().getDeclaredFields()) {
try {
Object value = field.get(expected);
if(value != null && !value.equals(field.get(message))) {
throw new IllegalArgumentException("[TEST] Field " + field.getName() + " expected to be '" + value + "' but was '" + field.get(message) + "'");
}
}catch(IllegalAccessException ignore) { }
}
return true;
}else {
throw new IllegalArgumentException("[TEST] Response in test call could not be deserialized!");
}
}
@AfterAll
static void stop() {
serverMock.close();
}
}