From 805e8e5f9e7cceb3ec351123ac9b0a77cbefee53 Mon Sep 17 00:00:00 2001 From: punchready Date: Tue, 8 Jun 2021 16:04:46 +0200 Subject: [PATCH] wip: switch to synchronized handling during testing --- .../server/lobbymanager/LobbyConnection.java | 22 ++++++++++++++++- .../server/lobbymanager/LobbyRunner.java | 21 +++++++++------- .../marvelous/server/BaseGameLogicTest.java | 20 ++++++++++++++++ .../marvelous/server/MarvelousServerTest.java | 24 +++++++++++++++---- 4 files changed, 73 insertions(+), 14 deletions(-) diff --git a/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyConnection.java b/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyConnection.java index 0483fa2..f9c9939 100644 --- a/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyConnection.java +++ b/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyConnection.java @@ -21,6 +21,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; public class LobbyConnection implements Runnable { + private static boolean synchronous = false; + public final String gameID; public LobbyConnectionState state = LobbyConnectionState.Waiting; @@ -127,6 +129,11 @@ public class LobbyConnection implements Runnable { public void handleMessage(Participant participant, Request[] requests) { + if(synchronous) { + lobby.receiveRequests(requests, participant); + return; + } + try { this.requestQueue.put(Tuple.of(participant, requests)); } catch (InterruptedException ignored) { @@ -151,6 +158,11 @@ public class LobbyConnection implements Runnable { } + public void runSynchronous() { + synchronous = true; + run(); + } + @Override public void run() { state = LobbyConnectionState.Started; @@ -161,7 +173,11 @@ public class LobbyConnection implements Runnable { spectator.state = ParticipantState.Playing; } - Logger.info("Starting Lobby thread for lobby '{}'", gameID); + if(!synchronous) { + Logger.info("Starting Lobby thread for lobby '{}'", gameID); + }else { + Logger.info("Starting Lobby in main thread for lobby '{}'", gameID); + } sendGameStructure(true, true, true); @@ -175,6 +191,10 @@ public class LobbyConnection implements Runnable { selection.get(player2.id) ); + if(synchronous) { + return; + } + while (state == LobbyConnectionState.Started) { Tuple currentRequests = pollQueueAsync(); diff --git a/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyRunner.java b/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyRunner.java index 8c61f86..77bff62 100644 --- a/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyRunner.java +++ b/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyRunner.java @@ -4,11 +4,14 @@ import org.tinylog.Logger; import uulm.teamname.marvelous.server.Server; import java.util.HashMap; +import java.util.concurrent.Future; /** * Class meant for running lobbies. It manages said lobbies, creates threads for it, and moves it into an executor */ public class LobbyRunner { + private static boolean synchronous = false; + private static LobbyRunner instance; static LobbyRunner getInstance() { @@ -31,16 +34,16 @@ public class LobbyRunner { synchronized (activeLobbies) { if (activeLobbies.containsKey(connection)) { Logger.warn("Already active lobby was started again. This is probably a bug."); - } else if (!canAddLobby()) { - Logger.warn("Scheduling lobby to be started while max lobbies is reached. This might be a bug."); - Thread lobbyThread = new Thread(connection, "Lobby-" + connection.gameID); - activeLobbies.put(connection, lobbyThread); - lobbyThread.start(); } else { - Logger.trace("Executing LobbyThread 'Lobby-{}'...", connection.gameID); - Thread lobbyThread = new Thread(connection, "Lobby-" + connection.gameID); - activeLobbies.put(connection, lobbyThread); - lobbyThread.start(); + if(!synchronous) { + Logger.trace("Executing LobbyThread 'Lobby-{}'...", connection.gameID); + Thread lobbyThread = new Thread(connection, "Lobby-" + connection.gameID); + activeLobbies.put(connection, lobbyThread); + lobbyThread.start(); + }else { + Logger.trace("Executing Lobby 'Lobby-{}'...", connection.gameID); + connection.runSynchronous(); + } } } } diff --git a/Server/src/test/java/uulm/teamname/marvelous/server/BaseGameLogicTest.java b/Server/src/test/java/uulm/teamname/marvelous/server/BaseGameLogicTest.java index 2ea0db9..1d3084e 100644 --- a/Server/src/test/java/uulm/teamname/marvelous/server/BaseGameLogicTest.java +++ b/Server/src/test/java/uulm/teamname/marvelous/server/BaseGameLogicTest.java @@ -1,7 +1,9 @@ package uulm.teamname.marvelous.server; import uulm.teamname.marvelous.gamelibrary.config.*; +import uulm.teamname.marvelous.server.lobbymanager.LobbyRunner; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Iterator; import java.util.concurrent.ThreadLocalRandom; @@ -26,6 +28,12 @@ public class BaseGameLogicTest { partyConfig.timeStoneCD = 7; partyConfig.mindStoneDMG = 3; + partyConfig.maxRoundTime = 1000; + partyConfig.maxGameTime = 1000; + partyConfig.maxAnimationTime = 1000; + partyConfig.maxResponseTime = 1000; + partyConfig.maxPauseTime = 1000; + characterConfig.characters = new CharacterProperties[24]; for(int i = 0; i < characterConfig.characters.length; i++) { characterConfig.characters[i] = generateCharacter(i); @@ -78,4 +86,16 @@ public class BaseGameLogicTest { return props; } + + static void setPrivateFinalBoolean(Class c, String name, boolean value) throws NoSuchFieldException, IllegalAccessException { + Field field = LobbyRunner.class.getDeclaredField(name); + field.setAccessible(true); + + //this is broken somehow + //Field modifiersField = Field.class.getDeclaredField("modifiers"); + //modifiersField.setAccessible(true); + //modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + + field.set(null, value); + } } diff --git a/Server/src/test/java/uulm/teamname/marvelous/server/MarvelousServerTest.java b/Server/src/test/java/uulm/teamname/marvelous/server/MarvelousServerTest.java index f7fbfa7..bc441e8 100644 --- a/Server/src/test/java/uulm/teamname/marvelous/server/MarvelousServerTest.java +++ b/Server/src/test/java/uulm/teamname/marvelous/server/MarvelousServerTest.java @@ -12,7 +12,9 @@ import uulm.teamname.marvelous.gamelibrary.messages.client.CharacterSelectionMes 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.LobbyConnection; import uulm.teamname.marvelous.server.lobbymanager.LobbyManager; +import uulm.teamname.marvelous.server.lobbymanager.LobbyRunner; import uulm.teamname.marvelous.server.netconnector.UserManager; import java.lang.reflect.Constructor; @@ -29,7 +31,7 @@ class MarvelousServerTest extends BaseGameLogicTest { private static JSON json; @BeforeAll - static void start() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { + static void start() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException { Constructor um = UserManager.class.getDeclaredConstructor(); um.setAccessible(true); um.newInstance(); @@ -41,6 +43,9 @@ class MarvelousServerTest extends BaseGameLogicTest { generate(); + setPrivateFinalBoolean(LobbyConnection.class, "synchronous", true); + setPrivateFinalBoolean(LobbyRunner.class, "synchronous", true); + serverMock.when(Server::getMaxLobbies).thenReturn(10); serverMock.when(Server::getPartyConfig).thenReturn(partyConfig); serverMock.when(Server::getScenarioConfig).thenReturn(scenarioConfig); @@ -66,6 +71,11 @@ class MarvelousServerTest extends BaseGameLogicTest { WebSocket s1 = mock(WebSocket.class); WebSocket s2 = mock(WebSocket.class); + when(p1.getResourceDescriptor()).thenReturn("/"); + when(p2.getResourceDescriptor()).thenReturn("/"); + when(s1.getResourceDescriptor()).thenReturn("/"); + when(s2.getResourceDescriptor()).thenReturn("/"); + m.connectUser(p1); ensureHandshake(m, p1, "Player 1", "1234", false); @@ -83,14 +93,14 @@ class MarvelousServerTest extends BaseGameLogicTest { 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()); - */ + + System.out.println("hi"); } private void ensureHandshake(UserManager m, WebSocket c, String name, String deviceID, boolean runningGame) { @@ -179,7 +189,13 @@ class MarvelousServerTest extends BaseGameLogicTest { for(Field field: expected.getClass().getDeclaredFields()) { try { Object value = field.get(expected); - if(value != null && !value.equals(field.get(message))) { + Object actualValue; + try { + actualValue = field.get(message); + }catch(IllegalArgumentException e) { + throw new IllegalArgumentException("[TEST] Response message expected to be '" + expected.getClass().getName() + "' but was '" + message.getClass().getName() + "'"); + } + if(value != null && !value.equals(actualValue)) { throw new IllegalArgumentException("[TEST] Field " + field.getName() + " expected to be '" + value + "' but was '" + field.get(message) + "'"); } }catch(IllegalAccessException ignore) { }