From b55639864a0fadf34fcdd130c4a0262a22dd7aa8 Mon Sep 17 00:00:00 2001 From: zargess Date: Wed, 16 Jul 2025 10:11:14 +0200 Subject: [PATCH 1/2] ConversationHandler Tests Testing the ConversationHandler class to 100% test and pitest coverage --- .../fagi/handler/ConversationHandlerTest.java | 222 ++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 fagiServer/src/test/java/com/fagi/handler/ConversationHandlerTest.java diff --git a/fagiServer/src/test/java/com/fagi/handler/ConversationHandlerTest.java b/fagiServer/src/test/java/com/fagi/handler/ConversationHandlerTest.java new file mode 100644 index 00000000..b17150f7 --- /dev/null +++ b/fagiServer/src/test/java/com/fagi/handler/ConversationHandlerTest.java @@ -0,0 +1,222 @@ +package com.fagi.handler; + +import com.fagi.conversation.Conversation; +import com.fagi.conversation.ConversationType; +import com.fagi.model.Data; +import com.fagi.model.User; +import com.fagi.model.messages.message.TextMessage; +import com.fagi.util.DataTestUtil; +import com.fagi.worker.OutputAgent; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +class ConversationHandlerTest { + private Data data; + private ConversationHandler conversationHandler; + + @BeforeEach + void setUp() { + data = Mockito.mock(Data.class); + conversationHandler = new ConversationHandler(data); + } + + @Test + void givenMessageAddedToConversationHandler_ThenQueueSizeShouldBeOne() { + conversationHandler.addMessage(new TextMessage( + "Test message", + "bob", + 42 + )); + + Assertions.assertEquals( + 1, + conversationHandler.queueSize() + ); + } + + @Test + void givenMessageInQueue_WhenRunningTick_ThenQueueSizeShouldBeZeroAfter() { + var conversation = new Conversation( + 42, + "Test conversation", + ConversationType.Single + ); + + Mockito + .when(data.getConversation(conversation.getId())) + .thenReturn(conversation); + + conversationHandler.addMessage(new TextMessage( + "Test message", + "bob", + conversation.getId() + )); + + conversationHandler.tick(); + + Assertions.assertEquals( + 0, + conversationHandler.queueSize() + ); + } + + @Test + void givenMessageInQueue_WhenRunningTick_ThenShouldStoreConversationWithMessage() { + var conversation = new Conversation( + 42, + "Test conversation", + ConversationType.Single + ); + + Mockito + .when(data.getConversation(conversation.getId())) + .thenReturn(conversation); + + TextMessage message = new TextMessage( + "Test message", + "bob", + conversation.getId() + ); + conversationHandler.addMessage(message); + + conversationHandler.tick(); + + ArgumentCaptor conversationArgumentCaptor = DataTestUtil.verifyStoreConversationCalled( + data, + 1 + ); + Conversation capturedConversation = conversationArgumentCaptor.getValue(); + + Assertions.assertAll( + () -> Assertions.assertEquals( + conversation.getId(), + capturedConversation.getId() + ), + () -> Assertions.assertEquals( + 1, + capturedConversation + .getMessages() + .size() + ), + () -> Assertions.assertEquals( + message, + capturedConversation + .getMessages() + .getFirst() + ) + ); + } + + @Test + void givenMessageInQueue_WhenTwoOfThreeParticipantsAreOnline_ThenOnlyTheOnlineParticipantsShouldReceiveTheMessage() { + var user1 = new User( + "bob", + "1234" + ); + var outputAgent1 = Mockito.mock(OutputAgent.class); + var user2 = new User( + "eva", + "1234" + ); + var outputAgent2 = Mockito.mock(OutputAgent.class); + var user3 = new User( + "alice", + "1234" + ); + var outputAgent3 = Mockito.mock(OutputAgent.class); + + var conversation = new Conversation( + 42, + "Test Conversation", + ConversationType.Single + ); + conversation.addUser(user1.getUserName()); + conversation.addUser(user2.getUserName()); + conversation.addUser(user3.getUserName()); + + Mockito + .when(data.getConversation(conversation.getId())) + .thenReturn(conversation); + + Mockito + .when(data.isUserOnline(user1.getUserName())) + .thenReturn(false); + Mockito + .when(data.isUserOnline(user2.getUserName())) + .thenReturn(true); + Mockito + .when(data.isUserOnline(user3.getUserName())) + .thenReturn(true); + + Mockito + .when(data.getOutputAgent(user1.getUserName())) + .thenReturn(outputAgent1); + Mockito + .when(data.getOutputAgent(user2.getUserName())) + .thenReturn(outputAgent2); + Mockito + .when(data.getOutputAgent(user3.getUserName())) + .thenReturn(outputAgent3); + + var message = new TextMessage( + "Test message", + user2.getUserName(), + conversation.getId() + ); + + conversationHandler.addMessage(message); + + conversationHandler.tick(); + + Mockito + .verify( + outputAgent1, + Mockito.times(0) + ) + .addMessage(Mockito.any()); + Mockito + .verify( + outputAgent2, + Mockito.times(1) + ) + .addMessage(Mockito.eq(message)); + Mockito + .verify( + outputAgent3, + Mockito.times(1) + ) + .addMessage(Mockito.eq(message)); + } + + @Test + void dummy() throws InterruptedException { + var outContent = new ByteArrayOutputStream(); + var errorContent = new ByteArrayOutputStream(); + System.setErr(new PrintStream(errorContent)); + System.setOut(new PrintStream(outContent)); + + var thread = new Thread(conversationHandler); + thread.setDaemon(true); + + thread.start(); + + Thread.sleep(100); + + thread.interrupt(); + + Assertions.assertAll( + () -> Assertions.assertTrue(errorContent.toString().contains("java.lang.InterruptedException")), + () -> Assertions.assertFalse(outContent.toString().contains("java.lang.InterruptedException")), + () -> Assertions.assertTrue(thread.isInterrupted()) + ); + + System.setErr(System.err); + System.setOut(System.out); + } +} \ No newline at end of file From a0a56913cfff205513d07309480423d459e72aa2 Mon Sep 17 00:00:00 2001 From: zargess Date: Wed, 16 Jul 2025 15:24:52 +0200 Subject: [PATCH 2/2] Rework isRunning ## Move running field Removed the running fields for all Workers and the Server class. Now the running field is contained in the CheckFieldRunningStrategy. ## Stop IsRunningStrategy The IsRunningStrategy now has a function to stop the strategy. In the CheckFieldRunningStrategy it sets the running field to false. --- .../java/com/fagi/handler/InputHandler.java | 4 +- .../running/CheckFieldRunningStrategy.java | 18 +++++ .../com/fagi/running/IsRunningStrategy.java | 5 ++ .../src/main/java/com/fagi/server/Server.java | 13 +-- .../CheckFieldServerRunningStrategy.java | 23 ------ .../main/java/com/fagi/worker/InputAgent.java | 2 +- .../java/com/fagi/worker/InputWorker.java | 14 ++-- .../java/com/fagi/worker/OutputAgent.java | 2 +- .../java/com/fagi/worker/OutputWorker.java | 10 +-- .../src/main/java/com/fagi/worker/Worker.java | 14 ++-- .../CheckFieldWorkerRunningStrategy.java | 23 ------ .../inputhandler/LogoutServerTests.java | 18 +---- .../com/fagi/server/ServerConfigTests.java | 10 +++ .../ServerConversationHandlerTests.java | 46 +++++++---- .../com/fagi/server/ServerLoggingTests.java | 7 +- .../com/fagi/server/ServerWorkerTests.java | 81 ++++++++++++------- .../CheckFieldServerRunningStrategyTest.java | 46 ----------- .../java/com/fagi/util/NeverRunStrategy.java | 17 ++++ .../java/com/fagi/util/RunOnceStrategy.java | 5 ++ .../com/fagi/worker/InputWorkerTests.java | 28 ++++--- .../com/fagi/worker/OutputWorkerTest.java | 48 +++++------ .../worker/WorkerRunCalledNTimesStrategy.java | 5 ++ 22 files changed, 212 insertions(+), 227 deletions(-) create mode 100644 fagiServer/src/main/java/com/fagi/running/CheckFieldRunningStrategy.java delete mode 100644 fagiServer/src/main/java/com/fagi/server/running/CheckFieldServerRunningStrategy.java delete mode 100644 fagiServer/src/main/java/com/fagi/worker/running/CheckFieldWorkerRunningStrategy.java delete mode 100644 fagiServer/src/test/java/com/fagi/server/running/CheckFieldServerRunningStrategyTest.java create mode 100644 fagiServer/src/test/java/com/fagi/util/NeverRunStrategy.java diff --git a/fagiServer/src/main/java/com/fagi/handler/InputHandler.java b/fagiServer/src/main/java/com/fagi/handler/InputHandler.java index e0e5168c..3d09fa62 100644 --- a/fagiServer/src/main/java/com/fagi/handler/InputHandler.java +++ b/fagiServer/src/main/java/com/fagi/handler/InputHandler.java @@ -61,7 +61,7 @@ public void handleInput(Object input) { out.addResponse(handleLogin(arg)); } else if (input instanceof Logout) { out.addResponse(handleLogout()); - out.setRunning(false); + out.stop(); } else if (input instanceof CreateUser arg) { out.addResponse(handleCreateUser(arg)); } else if (input instanceof FriendRequest arg) { @@ -420,7 +420,7 @@ private Object handleLogin(Login arg) { private Object handleLogout() { data.userLogout(inputAgent.getUsername()); - inputAgent.setRunning(false); + inputAgent.stop(); List friends = data .getUser(inputAgent.getUsername()) diff --git a/fagiServer/src/main/java/com/fagi/running/CheckFieldRunningStrategy.java b/fagiServer/src/main/java/com/fagi/running/CheckFieldRunningStrategy.java new file mode 100644 index 00000000..3af417f2 --- /dev/null +++ b/fagiServer/src/main/java/com/fagi/running/CheckFieldRunningStrategy.java @@ -0,0 +1,18 @@ +package com.fagi.running; + +/** + * Checks a field to determine if it's running. + */ +public class CheckFieldRunningStrategy implements IsRunningStrategy { + private boolean running = true; + + @Override + public boolean isRunning() { + return running; + } + + @Override + public void stop() { + running = false; + } +} diff --git a/fagiServer/src/main/java/com/fagi/running/IsRunningStrategy.java b/fagiServer/src/main/java/com/fagi/running/IsRunningStrategy.java index dc8082d2..5d0e7b23 100644 --- a/fagiServer/src/main/java/com/fagi/running/IsRunningStrategy.java +++ b/fagiServer/src/main/java/com/fagi/running/IsRunningStrategy.java @@ -11,4 +11,9 @@ public interface IsRunningStrategy { * @return true if the worker is running, false if not */ boolean isRunning(); + + /** + * Ensure future calls to {@link IsRunningStrategy#isRunning()} will return false + */ + void stop(); } diff --git a/fagiServer/src/main/java/com/fagi/server/Server.java b/fagiServer/src/main/java/com/fagi/server/Server.java index 5819144f..9beda6d7 100644 --- a/fagiServer/src/main/java/com/fagi/server/Server.java +++ b/fagiServer/src/main/java/com/fagi/server/Server.java @@ -12,8 +12,8 @@ import com.fagi.handler.ConversationHandler; import com.fagi.model.Data; import com.fagi.model.InviteCodeContainer; +import com.fagi.running.CheckFieldRunningStrategy; import com.fagi.running.IsRunningStrategy; -import com.fagi.server.running.CheckFieldServerRunningStrategy; import com.fagi.utility.JsonFileOperations; import com.fagi.worker.InputWorker; import com.fagi.worker.OutputWorker; @@ -32,8 +32,7 @@ public class Server { static final String CONFIG_FILE = "config/serverinfo.config"; private final Data data; - private IsRunningStrategy isRunningStrategy = new CheckFieldServerRunningStrategy(this); - private boolean running = true; + private IsRunningStrategy isRunningStrategy = new CheckFieldRunningStrategy(); private final ConversationHandler handler; private Thread conversationHandlerThread; private final List inputWorkerThreads = Collections.synchronizedList(new ArrayList<>()); @@ -82,7 +81,7 @@ public void start(ServerSocket serverSocket) { workerCreation(serverSocket); } catch (IOException e) { System.out.println("Error in server loop exception = " + e); - running = false; + isRunningStrategy.stop(); } } @@ -121,11 +120,7 @@ private void workerCreation(ServerSocket serverSocket) throws IOException { } public boolean isRunning() { - return running; - } - - public void setRunning(boolean running) { - this.running = running; + return isRunningStrategy.isRunning(); } public void setIsRunningStrategy(IsRunningStrategy isRunningStrategy) { diff --git a/fagiServer/src/main/java/com/fagi/server/running/CheckFieldServerRunningStrategy.java b/fagiServer/src/main/java/com/fagi/server/running/CheckFieldServerRunningStrategy.java deleted file mode 100644 index 8143bfff..00000000 --- a/fagiServer/src/main/java/com/fagi/server/running/CheckFieldServerRunningStrategy.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.fagi.server.running; - -import com.fagi.running.IsRunningStrategy; -import com.fagi.server.Server; - -/** - * This strategy simply returns the value of {@link Server#isRunning()} - */ -public class CheckFieldServerRunningStrategy implements IsRunningStrategy { - private final Server server; - - /** - * @param server the server the strategy should check on - */ - public CheckFieldServerRunningStrategy(Server server) { - this.server = server; - } - - @Override - public boolean isRunning() { - return server.isRunning(); - } -} diff --git a/fagiServer/src/main/java/com/fagi/worker/InputAgent.java b/fagiServer/src/main/java/com/fagi/worker/InputAgent.java index 5b39abf5..f9d87df0 100644 --- a/fagiServer/src/main/java/com/fagi/worker/InputAgent.java +++ b/fagiServer/src/main/java/com/fagi/worker/InputAgent.java @@ -13,7 +13,7 @@ public interface InputAgent { String getUsername(); - void setRunning(boolean running); + void stop(); InputHandler getInputHandler(); } diff --git a/fagiServer/src/main/java/com/fagi/worker/InputWorker.java b/fagiServer/src/main/java/com/fagi/worker/InputWorker.java index 8c2c03ff..e0eab39b 100644 --- a/fagiServer/src/main/java/com/fagi/worker/InputWorker.java +++ b/fagiServer/src/main/java/com/fagi/worker/InputWorker.java @@ -50,7 +50,7 @@ public InputWorker( @Override public void run() { - while (isWorkerRunningStrategy.isRunning()) { + while (isRunningStrategy.isRunning()) { System.out.println("Running"); try { Object input = objIn.readObject(); @@ -63,13 +63,13 @@ public void run() { // TODO: This will be fixed with https://trello.com/c/KBmf0o1U/54 inputHandler.handleInput(input); } catch (EOFException | SocketException eof) { - running = false; + stop(); System.out.println("Logging out user " + myUserName); - out.setRunning(false); + out.stop(); data.userLogout(myUserName); } catch (Exception e) { - running = false; - out.setRunning(false); + stop(); + out.stop(); System.out.println("Something went wrong in a input worker while loop " + e); e.printStackTrace(); System.out.println("Logging out user " + myUserName); @@ -115,8 +115,8 @@ public String getUsername() { } @Override - public void setRunning(boolean running) { - this.running = running; + public void stop() { + this.isRunningStrategy.stop(); } @Override diff --git a/fagiServer/src/main/java/com/fagi/worker/OutputAgent.java b/fagiServer/src/main/java/com/fagi/worker/OutputAgent.java index a03e3ed0..2fe4e09f 100644 --- a/fagiServer/src/main/java/com/fagi/worker/OutputAgent.java +++ b/fagiServer/src/main/java/com/fagi/worker/OutputAgent.java @@ -13,5 +13,5 @@ public interface OutputAgent { void setUserName(String userName); - void setRunning(boolean running); + void stop(); } diff --git a/fagiServer/src/main/java/com/fagi/worker/OutputWorker.java b/fagiServer/src/main/java/com/fagi/worker/OutputWorker.java index 6bdf7d7c..5203f6e4 100644 --- a/fagiServer/src/main/java/com/fagi/worker/OutputWorker.java +++ b/fagiServer/src/main/java/com/fagi/worker/OutputWorker.java @@ -44,20 +44,20 @@ public OutputWorker( @Override public void run() { - while (isWorkerRunningStrategy.isRunning()) { + while (isRunningStrategy.isRunning()) { System.out.println("Running"); try { sendIncMessages(); sendResponses(); objOut.reset(); - while (messages.isEmpty() && respondObjects.isEmpty() && isWorkerRunningStrategy.isRunning()) { + while (messages.isEmpty() && respondObjects.isEmpty() && isRunningStrategy.isRunning()) { if (myUserName != null) { checkForLists(); } Thread.sleep(100); } } catch (IOException | InterruptedException ioe) { - running = false; + stop(); System.out.println(ioe.toString()); System.out.println("Logging out user " + myUserName); data.userLogout(myUserName); @@ -134,8 +134,8 @@ public void setUserName(String userName) { } @Override - public void setRunning(boolean running) { - this.running = running; + public void stop() { + this.isRunningStrategy.stop(); } public int getResponseObjectsQueueSize() { diff --git a/fagiServer/src/main/java/com/fagi/worker/Worker.java b/fagiServer/src/main/java/com/fagi/worker/Worker.java index 422fa3ad..05ea35b2 100644 --- a/fagiServer/src/main/java/com/fagi/worker/Worker.java +++ b/fagiServer/src/main/java/com/fagi/worker/Worker.java @@ -6,24 +6,22 @@ * * Worker thread for each client. */ -import com.fagi.worker.running.CheckFieldWorkerRunningStrategy; + +import com.fagi.running.CheckFieldRunningStrategy; import com.fagi.running.IsRunningStrategy; public abstract class Worker implements Runnable { - // TODO: Rework using running and the IsWorkerRunningStrategy - // Trello issue: https://trello.com/c/8cEhrobt - boolean running = true; - protected IsRunningStrategy isWorkerRunningStrategy = new CheckFieldWorkerRunningStrategy(this); + protected IsRunningStrategy isRunningStrategy = new CheckFieldRunningStrategy(); public boolean isRunning() { - return running; + return isRunningStrategy.isRunning(); } /** * Used by tests to change the strategy used to check if worker is running * @param strategy the strategy to set */ - void setIsWorkerRunningStrategy(IsRunningStrategy strategy) { - isWorkerRunningStrategy = strategy; + void setIsRunningStrategy(IsRunningStrategy strategy) { + isRunningStrategy = strategy; } } \ No newline at end of file diff --git a/fagiServer/src/main/java/com/fagi/worker/running/CheckFieldWorkerRunningStrategy.java b/fagiServer/src/main/java/com/fagi/worker/running/CheckFieldWorkerRunningStrategy.java deleted file mode 100644 index e01bfd3e..00000000 --- a/fagiServer/src/main/java/com/fagi/worker/running/CheckFieldWorkerRunningStrategy.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.fagi.worker.running; - -import com.fagi.running.IsRunningStrategy; -import com.fagi.worker.Worker; - -/** - * This strategy simply returns the value of {@link Worker#isRunning()} - */ -public class CheckFieldWorkerRunningStrategy implements IsRunningStrategy { - private final Worker worker; - - /** - * @param worker the worker the strategy should check on - */ - public CheckFieldWorkerRunningStrategy(Worker worker) { - this.worker = worker; - } - - @Override - public boolean isRunning() { - return worker.isRunning(); - } -} diff --git a/fagiServer/src/test/java/com/fagi/handler/inputhandler/LogoutServerTests.java b/fagiServer/src/test/java/com/fagi/handler/inputhandler/LogoutServerTests.java index 2c50ac08..5c279b3c 100644 --- a/fagiServer/src/test/java/com/fagi/handler/inputhandler/LogoutServerTests.java +++ b/fagiServer/src/test/java/com/fagi/handler/inputhandler/LogoutServerTests.java @@ -99,38 +99,24 @@ void handlingLogoutRequest_ShouldResultInAllIsWellResponse() { void handlingLogoutRequest_ShouldResultInOutputWorkerNotRunning() { inputHandler.handleInput(new Logout()); - var argumentCaptor = ArgumentCaptor.forClass(Boolean.class); Mockito .verify( outputAgent, times(1) ) - .setRunning(argumentCaptor.capture()); - - Boolean isRunning = argumentCaptor.getValue(); - Assertions.assertAll( - () -> Assertions.assertNotNull(isRunning), - () -> Assertions.assertFalse(isRunning) - ); + .stop(); } @Test void handlingLogoutRequest_ShouldResultInInputAgentNotRunning() { inputHandler.handleInput(new Logout()); - var argumentCaptor = ArgumentCaptor.forClass(Boolean.class); Mockito .verify( inputAgent, times(1) ) - .setRunning(argumentCaptor.capture()); - - Boolean isRunning = argumentCaptor.getValue(); - Assertions.assertAll( - () -> Assertions.assertNotNull(isRunning), - () -> Assertions.assertFalse(isRunning) - ); + .stop(); } @Test diff --git a/fagiServer/src/test/java/com/fagi/server/ServerConfigTests.java b/fagiServer/src/test/java/com/fagi/server/ServerConfigTests.java index 08deab29..801b7a34 100644 --- a/fagiServer/src/test/java/com/fagi/server/ServerConfigTests.java +++ b/fagiServer/src/test/java/com/fagi/server/ServerConfigTests.java @@ -71,4 +71,14 @@ void whenServerConfigExists_ThenConfigContainsValidServerConfiguration() throws } ); } + + @Test + void givenServerNewlyCreated_ThenShouldBeRunning() { + var server = new Server( + serverPort, + data + ); + + Assertions.assertTrue(server.isRunning()); + } } diff --git a/fagiServer/src/test/java/com/fagi/server/ServerConversationHandlerTests.java b/fagiServer/src/test/java/com/fagi/server/ServerConversationHandlerTests.java index 6ad05480..69cd97af 100644 --- a/fagiServer/src/test/java/com/fagi/server/ServerConversationHandlerTests.java +++ b/fagiServer/src/test/java/com/fagi/server/ServerConversationHandlerTests.java @@ -4,7 +4,9 @@ import com.fagi.conversation.ConversationType; import com.fagi.model.Data; import com.fagi.model.messages.message.TextMessage; +import com.fagi.running.IsRunningStrategy; import com.fagi.util.DataTestUtil; +import com.fagi.util.NeverRunStrategy; import com.fagi.utility.JsonFileOperations; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -20,8 +22,10 @@ void whenServerIsStarted_ThenConversationHandlerThreadIsStartedAsDaemon() throws serverPort, data ); - server.setRunning(false); + server.setIsRunningStrategy(new NeverRunStrategy()); server.start(null); + + // Allow the ConversationHandler thread to get going Thread.sleep(100); Assertions.assertAll( @@ -33,14 +37,17 @@ void whenServerIsStarted_ThenConversationHandlerThreadIsStartedAsDaemon() throws } @Test - void whenServerIsShuttingDown_ThenConversationHandlerThreadShouldBeInterrupted() { + void whenServerIsShuttingDown_ThenConversationHandlerThreadShouldBeInterrupted() throws InterruptedException { var server = new Server( serverPort, data ); - server.setRunning(false); + server.setIsRunningStrategy(new NeverRunStrategy()); server.start(null); + // Allow the ConversationHandler thread to get going + Thread.sleep(100); + Assertions.assertTrue(server .getConversationHandlerThread() .isInterrupted()); @@ -67,7 +74,6 @@ void givenConversationHandlerHasMessage_WhenServerIsRunning_ThenConversationShou serverPort, data ); - server.setRunning(false); TextMessage evaMessage = new TextMessage( "Hello, friend.", "Eva", @@ -76,17 +82,25 @@ void givenConversationHandlerHasMessage_WhenServerIsRunning_ThenConversationShou server .getHandler() .addMessage(evaMessage); - server.setIsRunningStrategy(() -> { - do { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } while (server - .getHandler() - .queueSize() > 0); - return false; + server.setIsRunningStrategy(new IsRunningStrategy() { + @Override + public boolean isRunning() { + do { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } while (server + .getHandler() + .queueSize() > 0); + return false; + } + + @Override + public void stop() { + + } }); server.start(null); @@ -143,7 +157,7 @@ void givenConversationFileExists_WhenServerIsStarting_ThenConversationsShouldBeL serverPort, data ); - server.setRunning(false); + server.setIsRunningStrategy(new NeverRunStrategy()); server.start(null); diff --git a/fagiServer/src/test/java/com/fagi/server/ServerLoggingTests.java b/fagiServer/src/test/java/com/fagi/server/ServerLoggingTests.java index fa93d199..89733789 100644 --- a/fagiServer/src/test/java/com/fagi/server/ServerLoggingTests.java +++ b/fagiServer/src/test/java/com/fagi/server/ServerLoggingTests.java @@ -1,5 +1,6 @@ package com.fagi.server; +import com.fagi.util.NeverRunStrategy; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -94,7 +95,7 @@ void givenServerSocketCloseThrowsIOException_ThenShouldPrintErrorToSysErrorButNo serverPort, data ); - server.setRunning(false); + server.setIsRunningStrategy(new NeverRunStrategy()); server.start(serverSocket); Assertions.assertAll( @@ -117,7 +118,7 @@ void whenServerStarts_ThenStartingServerIsPrintedInSysOut() { serverPort, data ); - server.setRunning(false); + server.setIsRunningStrategy(new NeverRunStrategy()); server.start(null); Assertions.assertTrue(outContent @@ -134,7 +135,7 @@ void whenServerStops_ThenStoppingServerIsPrintedInSysOut() { serverPort, data ); - server.setRunning(false); + server.setIsRunningStrategy(new NeverRunStrategy()); server.start(null); Assertions.assertTrue(outContent diff --git a/fagiServer/src/test/java/com/fagi/server/ServerWorkerTests.java b/fagiServer/src/test/java/com/fagi/server/ServerWorkerTests.java index d3c05946..ced9ef77 100644 --- a/fagiServer/src/test/java/com/fagi/server/ServerWorkerTests.java +++ b/fagiServer/src/test/java/com/fagi/server/ServerWorkerTests.java @@ -10,6 +10,7 @@ import com.fagi.model.User; import com.fagi.model.messages.message.TextMessage; import com.fagi.responses.AllIsWell; +import com.fagi.running.IsRunningStrategy; import com.fagi.util.DataTestUtil; import com.fagi.util.RunOnceStrategy; import org.junit.jupiter.api.Assertions; @@ -46,16 +47,24 @@ void givenServerSocketAcceptsConnection_ThenShouldCreateInputAndOutputWorkerThre data ); var runStrategy = new RunOnceStrategy(); - server.setIsRunningStrategy(() -> { - var isRunning = runStrategy.isRunning(); - if (!isRunning) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - throw new RuntimeException(e); + server.setIsRunningStrategy(new IsRunningStrategy() { + @Override + public boolean isRunning() { + var isRunning = runStrategy.isRunning(); + if (!isRunning) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } } + return isRunning; + } + + @Override + public void stop() { + } - return isRunning; }); server.start(serverSocket); @@ -105,19 +114,27 @@ void givenServerSocketAcceptsConnection_ThenShouldProcessInputFromInputStreamAnd data ); var runStrategy = new RunOnceStrategy(); - server.setIsRunningStrategy(() -> { - var isRunning = runStrategy.isRunning(); - if (!isRunning) { - // Wait for output stream to contain response - while (outputStream.size() < encryptedResponse.length) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - throw new RuntimeException(e); + server.setIsRunningStrategy(new IsRunningStrategy() { + @Override + public boolean isRunning() { + var isRunning = runStrategy.isRunning(); + if (!isRunning) { + // Wait for output stream to contain response + while (outputStream.size() < encryptedResponse.length) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } } } + return isRunning; + } + + @Override + public void stop() { + } - return isRunning; }); server.start(serverSocket); @@ -196,19 +213,27 @@ void givenUserSendingTextMessage_WhenServerIsRunning_ThenConversationShouldConta ); var runStrategy = new RunOnceStrategy(); - server.setIsRunningStrategy(() -> { - var isRunning = runStrategy.isRunning(); - if (!isRunning) { - // Wait for output stream to contain response - while (outputStream.size() < encryptedResponse.length * 3) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - throw new RuntimeException(e); + server.setIsRunningStrategy(new IsRunningStrategy() { + @Override + public boolean isRunning() { + var isRunning = runStrategy.isRunning(); + if (!isRunning) { + // Wait for output stream to contain response + while (outputStream.size() < encryptedResponse.length * 3) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } } } + return isRunning; + } + + @Override + public void stop() { + } - return isRunning; }); server.start(serverSocket); diff --git a/fagiServer/src/test/java/com/fagi/server/running/CheckFieldServerRunningStrategyTest.java b/fagiServer/src/test/java/com/fagi/server/running/CheckFieldServerRunningStrategyTest.java deleted file mode 100644 index a1e4e6d5..00000000 --- a/fagiServer/src/test/java/com/fagi/server/running/CheckFieldServerRunningStrategyTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.fagi.server.running; - -import com.fagi.model.Data; -import com.fagi.server.Server; -import com.fagi.utility.JsonFileOperations; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.io.File; - -class CheckFieldServerRunningStrategyTest { - @AfterEach - void tearDown() { - var configFolder = new File(JsonFileOperations.CONFIG_FOLDER_PATH); - - if (configFolder.exists()) { - configFolder.delete(); - } - } - - @Test - void givenServerIsRunning_WhenCallingStrategy_ThenShouldReturnTrue() { - var server = new Server( - 4242, - new Data() - ); - - var strategy = new CheckFieldServerRunningStrategy(server); - - Assertions.assertTrue(strategy.isRunning()); - } - - @Test - void givenServerNotIsRunning_WhenCallingStrategy_ThenShouldReturnFalse() { - var server = new Server( - 4242, - new Data() - ); - server.setRunning(false); - - var strategy = new CheckFieldServerRunningStrategy(server); - - Assertions.assertFalse(strategy.isRunning()); - } -} \ No newline at end of file diff --git a/fagiServer/src/test/java/com/fagi/util/NeverRunStrategy.java b/fagiServer/src/test/java/com/fagi/util/NeverRunStrategy.java new file mode 100644 index 00000000..d1ca6019 --- /dev/null +++ b/fagiServer/src/test/java/com/fagi/util/NeverRunStrategy.java @@ -0,0 +1,17 @@ +package com.fagi.util; + +import com.fagi.running.IsRunningStrategy; + +/** + * An IsRunningStrategy that always returns false + */ +public class NeverRunStrategy implements IsRunningStrategy { + @Override + public boolean isRunning() { + return false; + } + + @Override + public void stop() { + } +} diff --git a/fagiServer/src/test/java/com/fagi/util/RunOnceStrategy.java b/fagiServer/src/test/java/com/fagi/util/RunOnceStrategy.java index 80ac07da..0640b3c0 100644 --- a/fagiServer/src/test/java/com/fagi/util/RunOnceStrategy.java +++ b/fagiServer/src/test/java/com/fagi/util/RunOnceStrategy.java @@ -17,4 +17,9 @@ public boolean isRunning() { hasRun = true; return true; } + + @Override + public void stop() { + hasRun = true; + } } diff --git a/fagiServer/src/test/java/com/fagi/worker/InputWorkerTests.java b/fagiServer/src/test/java/com/fagi/worker/InputWorkerTests.java index 125425fd..c5b3d1b0 100644 --- a/fagiServer/src/test/java/com/fagi/worker/InputWorkerTests.java +++ b/fagiServer/src/test/java/com/fagi/worker/InputWorkerTests.java @@ -12,6 +12,7 @@ import com.fagi.model.Session; import com.fagi.model.UserNameAvailableRequest; import com.fagi.responses.AllIsWell; +import com.fagi.util.NeverRunStrategy; import com.fagi.util.OutputAgentTestUtil; import com.fagi.util.RunOnceStrategy; import org.junit.jupiter.api.AfterEach; @@ -112,7 +113,7 @@ void givenRunningIsSetToFalse_WhenWorkerIsRunning_ThenShouldNotPrintRunningToCon var outContent = new ByteArrayOutputStream(); System.setOut(new PrintStream(outContent)); - inputWorker.setRunning(false); + inputWorker.setIsRunningStrategy(new NeverRunStrategy()); inputWorker.run(); @@ -125,7 +126,7 @@ void givenRunningIsSetToFalse_WhenWorkerIsRunning_ThenShouldPrintClosingInputToC var outContent = new ByteArrayOutputStream(); System.setOut(new PrintStream(outContent)); - inputWorker.setRunning(false); + inputWorker.setIsRunningStrategy(new NeverRunStrategy()); inputWorker.run(); @@ -146,7 +147,7 @@ void givenRunningIsSetToTrue_WhenWorkerIsRunning_ThenShouldPrintRunningToConsole var outContent = new ByteArrayOutputStream(); System.setOut(new PrintStream(outContent)); - inputWorker.setIsWorkerRunningStrategy(new RunOnceStrategy()); + inputWorker.setIsRunningStrategy(new RunOnceStrategy()); inputWorker.setSessionCreated(true); inputWorker.setAes(mockAes); @@ -177,7 +178,7 @@ void givenSessionIsNotCreated_WhenWorkerReceivesEncryptedObject_ThenRSADecryptio .when(() -> Conversion.convertFromBytes(decryptedInput)) .thenReturn(sessionRequest); - inputWorker.setIsWorkerRunningStrategy(new RunOnceStrategy()); + inputWorker.setIsRunningStrategy(new RunOnceStrategy()); Assertions.assertFalse(inputWorker.isSessionCreated()); @@ -218,7 +219,7 @@ void givenSessionCreated_WhenWorkerReceivesEncryptedObject_TheAESDecryptionIsCal .when(() -> Conversion.convertFromBytes(decryptedInput)) .thenReturn(loginRequest); - inputWorker.setIsWorkerRunningStrategy(new RunOnceStrategy()); + inputWorker.setIsRunningStrategy(new RunOnceStrategy()); inputWorker.setSessionCreated(true); inputWorker.setAes(mockedAES); @@ -248,7 +249,7 @@ void givenConversionFailsToConvertByteArrayToObject_WhenWorkerReceivesEncryptedO var outContent = new ByteArrayOutputStream(); System.setErr(new PrintStream(outContent)); - inputWorker.setIsWorkerRunningStrategy(new RunOnceStrategy()); + inputWorker.setIsRunningStrategy(new RunOnceStrategy()); inputWorker.setSessionCreated(true); inputWorker.setAes(mockedAES); @@ -274,7 +275,7 @@ void givenConversionFailsWithIo_WhenWorkerReceivesEncryptedObject_ThenSystemErro var outContent = new ByteArrayOutputStream(); System.setErr(new PrintStream(outContent)); - inputWorker.setIsWorkerRunningStrategy(new RunOnceStrategy()); + inputWorker.setIsRunningStrategy(new RunOnceStrategy()); inputWorker.setSessionCreated(true); inputWorker.setAes(mockedAES); @@ -312,7 +313,7 @@ void givenSocketException_WhenRunning_ThenShouldHandleUserLogoutGracefully() thr outputWorker, times(1) ) - .setRunning(false); + .stop(); Assertions.assertAll( () -> Assertions.assertFalse(inputWorker.isRunning()), @@ -352,7 +353,7 @@ void givenEOFException_WhenRunning_ThenShouldHandleUserLogoutGracefully() throws outputWorker, times(1) ) - .setRunning(false); + .stop(); Assertions.assertAll( () -> Assertions.assertFalse(inputWorker.isRunning()), @@ -392,7 +393,7 @@ void givenUnexpectedException_WhenRunning_ThenShouldHandleUserLogoutGracefullyBu outputWorker, times(1) ) - .setRunning(false); + .stop(); Assertions.assertAll( () -> Assertions.assertFalse(inputWorker.isRunning()), @@ -416,7 +417,7 @@ void givenRequestIsAJavaObject_WhenSendingUserNameAvailableRequest_ThenOutputWor when(data.getUser(any())).thenReturn(null); when(mockObjectInputStream.readObject()).thenReturn(new UserNameAvailableRequest("bob")); - inputWorker.setIsWorkerRunningStrategy(new RunOnceStrategy()); + inputWorker.setIsRunningStrategy(new RunOnceStrategy()); inputWorker.run(); @@ -425,4 +426,9 @@ void givenRequestIsAJavaObject_WhenSendingUserNameAvailableRequest_ThenOutputWor AllIsWell.class ); } + + @Test + void givenInputWorkerCreated_ThenShouldBeRunning() { + Assertions.assertTrue(inputWorker.isRunning()); + } } diff --git a/fagiServer/src/test/java/com/fagi/worker/OutputWorkerTest.java b/fagiServer/src/test/java/com/fagi/worker/OutputWorkerTest.java index 9ed2948e..d9e34c8b 100644 --- a/fagiServer/src/test/java/com/fagi/worker/OutputWorkerTest.java +++ b/fagiServer/src/test/java/com/fagi/worker/OutputWorkerTest.java @@ -12,6 +12,7 @@ import com.fagi.model.messages.message.TextMessage; import com.fagi.responses.AllIsWell; import com.fagi.responses.UserOnline; +import com.fagi.util.NeverRunStrategy; import com.fagi.util.RunOnceStrategy; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; @@ -55,6 +56,11 @@ void setUp() { outputWorker.setAes(aes); } + @Test + void givenOutputWorkerCreated_ThenShouldBeRunning() { + Assertions.assertTrue(outputWorker.isRunning()); + } + @Nested class OutputWorkerErrorHandlingTests { @AfterEach @@ -73,7 +79,7 @@ void givenWritingObjectGivesIOException_WhenRunningIsFalse_ThenShouldNotWriteToC doThrow(new IOException()) .when(objOut) .writeObject(any()); - outputWorker.setRunning(false); + outputWorker.setIsRunningStrategy(new NeverRunStrategy()); outputWorker.addResponse("dummy"); outputWorker.run(); @@ -93,7 +99,6 @@ void givenWritingObjectsGivesException_WhenRunningIsTrue_ThenRunningShouldBeSetT doThrow(new IOException()) .when(objOut) .writeObject(any()); - outputWorker.setRunning(true); outputWorker.addResponse("dummy"); outputWorker.run(); @@ -111,7 +116,6 @@ void givenWritingObjectsGivesIOException_WhenRunningIsTrue_ThenShouldWriteToCons doThrow(new IOException()) .when(objOut) .writeObject(any()); - outputWorker.setRunning(true); outputWorker.addResponse("dummy"); outputWorker.run(); @@ -134,7 +138,6 @@ void givenWritingObjectsGivesException_WhenRunningIsTrue_ThenShouldLogoutUser() doThrow(new IOException()) .when(objOut) .writeObject(any()); - outputWorker.setRunning(true); outputWorker.addResponse("dummy"); outputWorker.setUserName("bob"); @@ -252,8 +255,7 @@ void givenTwoListsHaveDifferentContent_WhenCallingEqualLists_ThenShouldReturnTru class OutputWorkerSendFriendRequestListTests { @Test void givenNoUsernameInOutputWorker_WhenCheckingFriendRequestList_ThenShouldNotSendFriendRequestList() throws IOException { - outputWorker.setIsWorkerRunningStrategy(new WorkerRunCalledNTimesStrategy(2)); - outputWorker.setRunning(true); + outputWorker.setIsRunningStrategy(new WorkerRunCalledNTimesStrategy(2)); outputWorker.run(); @@ -286,8 +288,7 @@ void givenMessageIsAddedToQueueAfterSendIncMessagesIsDone_WhenRunningIsTrue_Then .when(objOut) .reset(); - outputWorker.setIsWorkerRunningStrategy(new WorkerRunCalledNTimesStrategy(2)); - outputWorker.setRunning(true); + outputWorker.setIsRunningStrategy(new WorkerRunCalledNTimesStrategy(2)); outputWorker.setUserName(user.getUserName()); outputWorker.run(); @@ -334,8 +335,7 @@ void givenResponseIsAddedToQueueAfterSendIncResponsesIsDone_WhenRunningIsTrue_Th .when(objOut) .reset(); - outputWorker.setIsWorkerRunningStrategy(new WorkerRunCalledNTimesStrategy(2)); - outputWorker.setRunning(true); + outputWorker.setIsRunningStrategy(new WorkerRunCalledNTimesStrategy(2)); outputWorker.setUserName(user.getUserName()); outputWorker.run(); @@ -367,8 +367,7 @@ void givenUsernameIsSet_WhenCheckingFriendList_ThenShouldLookupUserFromData() { .when(data.getUser(user.getUserName())) .thenReturn(user); - outputWorker.setIsWorkerRunningStrategy(new WorkerRunCalledNTimesStrategy(2)); - outputWorker.setRunning(true); + outputWorker.setIsRunningStrategy(new WorkerRunCalledNTimesStrategy(2)); outputWorker.setUserName(user.getUserName()); outputWorker.run(); @@ -400,8 +399,7 @@ void givenUserHasNewFriendRequests_WhenCheckingFriendList_ThenShouldSendFriendRe .when(data.getUser(user.getUserName())) .thenReturn(user); - outputWorker.setIsWorkerRunningStrategy(new WorkerRunCalledNTimesStrategy(2)); - outputWorker.setRunning(true); + outputWorker.setIsRunningStrategy(new WorkerRunCalledNTimesStrategy(2)); outputWorker.setUserName(user.getUserName()); outputWorker.run(); @@ -435,8 +433,7 @@ void givenCheckingSameFriendRequestListTwice_WhenCheckingFriendList_ThenShouldSe .when(data.getUser(user.getUserName())) .thenReturn(user); - outputWorker.setIsWorkerRunningStrategy(new WorkerRunCalledNTimesStrategy(4)); - outputWorker.setRunning(true); + outputWorker.setIsRunningStrategy(new WorkerRunCalledNTimesStrategy(4)); outputWorker.setUserName(user.getUserName()); outputWorker.run(); @@ -453,8 +450,7 @@ void givenCheckingSameFriendRequestListTwice_WhenCheckingFriendList_ThenShouldSe @Test void whenCheckingFriendRequestListTwentyTimes_ThenRunShouldTakeAtLeastTwoSeconds() { - outputWorker.setIsWorkerRunningStrategy(new WorkerRunCalledNTimesStrategy(21)); - outputWorker.setRunning(true); + outputWorker.setIsRunningStrategy(new WorkerRunCalledNTimesStrategy(21)); var startTime = System.currentTimeMillis(); outputWorker.run(); @@ -476,8 +472,7 @@ void givenMessagesQueueHasTwoMessages_WhenRunningIsTrue_ThenHaveSentTwoObject() var user1LoggedInMessage = new UserLoggedIn("bob"); var user2LoggedInMessage = new UserLoggedIn("eve"); - outputWorker.setIsWorkerRunningStrategy(new RunOnceStrategy()); - outputWorker.setRunning(true); + outputWorker.setIsRunningStrategy(new RunOnceStrategy()); outputWorker.addMessage(user1LoggedInMessage); outputWorker.addMessage(user2LoggedInMessage); @@ -531,8 +526,7 @@ void givenResponseIsAddedToQueueAfterSendIncResponsesIsDone_WhenRunningBecomesFa .when(objOut) .reset(); - outputWorker.setIsWorkerRunningStrategy(new RunOnceStrategy()); - outputWorker.setRunning(true); + outputWorker.setIsRunningStrategy(new RunOnceStrategy()); outputWorker.run(); @@ -548,7 +542,7 @@ void givenResponseIsAddedToQueueAfterSendIncResponsesIsDone_WhenRunningBecomesFa @Test void whenRunningIsFalse_ThenShouldSendAllRespondObjects() throws IOException { - outputWorker.setRunning(false); + outputWorker.setIsRunningStrategy(new NeverRunStrategy()); String firstResponse = "some response"; AllIsWell secondResponse = new AllIsWell(); outputWorker.addResponse(firstResponse); @@ -598,7 +592,7 @@ void whenRunningIsFalse_ThenClosingOutputShouldBePrintedToConsole() { var outContent = new ByteArrayOutputStream(); System.setOut(new PrintStream(outContent)); - outputWorker.setRunning(false); + outputWorker.setIsRunningStrategy(new NeverRunStrategy()); outputWorker.run(); @@ -612,8 +606,7 @@ void whenRunningIsTrue_ThenRunningShouldBePrintedToConsole() { var outContent = new ByteArrayOutputStream(); System.setOut(new PrintStream(outContent)); - outputWorker.setIsWorkerRunningStrategy(new RunOnceStrategy()); - outputWorker.setRunning(true); + outputWorker.setIsRunningStrategy(new RunOnceStrategy()); outputWorker.run(); @@ -629,8 +622,7 @@ void givenMessagesQueueHasOneMessage_WhenRunningIsTrue_ThenHaveSentOneObject() t var userLoggedInMessage = new UserLoggedIn("bob"); - outputWorker.setIsWorkerRunningStrategy(new RunOnceStrategy()); - outputWorker.setRunning(true); + outputWorker.setIsRunningStrategy(new RunOnceStrategy()); outputWorker.addMessage(userLoggedInMessage); diff --git a/fagiServer/src/test/java/com/fagi/worker/WorkerRunCalledNTimesStrategy.java b/fagiServer/src/test/java/com/fagi/worker/WorkerRunCalledNTimesStrategy.java index ae497174..0dd9c107 100644 --- a/fagiServer/src/test/java/com/fagi/worker/WorkerRunCalledNTimesStrategy.java +++ b/fagiServer/src/test/java/com/fagi/worker/WorkerRunCalledNTimesStrategy.java @@ -14,4 +14,9 @@ public WorkerRunCalledNTimesStrategy(int timesToRun) { public boolean isRunning() { return timesToRun > timesCalled++; } + + @Override + public void stop() { + timesCalled = timesToRun; + } }