From 2342a51cbc3311f873286453ff45c0f4b3085878 Mon Sep 17 00:00:00 2001 From: Tiffany Bonzon Date: Thu, 19 Mar 2020 14:12:12 +0100 Subject: [PATCH 1/6] Specifications --- specs/tiffanybonzon/PROTOCOL.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 specs/tiffanybonzon/PROTOCOL.md diff --git a/specs/tiffanybonzon/PROTOCOL.md b/specs/tiffanybonzon/PROTOCOL.md new file mode 100644 index 0000000..870373d --- /dev/null +++ b/specs/tiffanybonzon/PROTOCOL.md @@ -0,0 +1,33 @@ +# Phase 1: write the specification +## What transport protocol do we use? +We use TCP + +## How does the client find the server (addresses and ports)? +The server can be reached by its IP address (127.0.0.1 if server and clients are on the same machine), and the port 2112 + +## Who speaks first? +The client initiates the exchange + +## What is the sequence of messages exchanged by the client and the server? (flow) +1. Client initializes connection ("Hello") +2. Servers answers with operation list ("OP : ADD SUB MULT DIV POW") +3. Client answers ("OP NUM1 NUM2") +4. Server sends answer +5. Server waits for next operation ("OP NUM1 NUM") or for client to end the session ("END") or times out after 60 seconds + +## What happens when a message is received from the other party? (semantics) +The server processes the requests +The client displays the answers + +## What is the syntax of the messages? How we generate and parse them? (syntax) +1. Initialization message: "HELLO" +2. First server reply: + "Available operations: ADD SUB MULT DIV POW. + Syntax: (Each element is separated by a space, decimal is specified with a dot)" +3. Client replies: "OP NUM1 NUM2" +4. Server return calc answer: "" or "Syntax Error / Operation unknown" +5. Client sends new calc or ends the session: "OP NUM1 NUM2" or "END" + +## Who closes the connection and when? +The clients can tell the server to close the connection by sending "END" +The server automatically closes the connection after 60 seconds of inactivity From b9d5422da289bc9e6e4b936ee9c82f0d89b20789 Mon Sep 17 00:00:00 2001 From: Tiffany Bonzon Date: Fri, 20 Mar 2020 15:15:57 +0100 Subject: [PATCH 2/6] Server implemented but not yet unit tested --- specs/tiffanybonzon/CalcServer/pom.xml | 57 ++++++ .../server/impl/tiffanybonzon/CalcServer.java | 14 ++ .../server/impl/tiffanybonzon/Server.java | 184 ++++++++++++++++++ .../server/tests/tiffanybonzon/InitTest.java | 12 ++ 4 files changed, 267 insertions(+) create mode 100644 specs/tiffanybonzon/CalcServer/pom.xml create mode 100644 specs/tiffanybonzon/CalcServer/src/main/java/server/impl/tiffanybonzon/CalcServer.java create mode 100644 specs/tiffanybonzon/CalcServer/src/main/java/server/impl/tiffanybonzon/Server.java create mode 100644 specs/tiffanybonzon/CalcServer/src/test/java/server/tests/tiffanybonzon/InitTest.java diff --git a/specs/tiffanybonzon/CalcServer/pom.xml b/specs/tiffanybonzon/CalcServer/pom.xml new file mode 100644 index 0000000..aa521ec --- /dev/null +++ b/specs/tiffanybonzon/CalcServer/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + res.tiffanybonzon + CalcServer + 1.0-SNAPSHOT + jar + + + + UTF-8 + 1.8 + 1.8 + + Calc Server + + + + org.junit.jupiter + junit-jupiter-api + 5.4.0 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.4.0 + test + + + junit + junit + 4.12 + test + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + server.impl.tiffanybonzon.CalcServer + + + + + + + + + \ No newline at end of file diff --git a/specs/tiffanybonzon/CalcServer/src/main/java/server/impl/tiffanybonzon/CalcServer.java b/specs/tiffanybonzon/CalcServer/src/main/java/server/impl/tiffanybonzon/CalcServer.java new file mode 100644 index 0000000..a29cb36 --- /dev/null +++ b/specs/tiffanybonzon/CalcServer/src/main/java/server/impl/tiffanybonzon/CalcServer.java @@ -0,0 +1,14 @@ +package server.impl.tiffanybonzon; + +/** + * Main class for the CalcServer + * Initializes the server on port 2112 as defined in our specifications + * + * @author Tiffany Bonzon + */ +public class CalcServer { + public static void main(String[] args) { + Server srv = new Server(2112); + srv.serveClients(); + } +} diff --git a/specs/tiffanybonzon/CalcServer/src/main/java/server/impl/tiffanybonzon/Server.java b/specs/tiffanybonzon/CalcServer/src/main/java/server/impl/tiffanybonzon/Server.java new file mode 100644 index 0000000..cdfab22 --- /dev/null +++ b/specs/tiffanybonzon/CalcServer/src/main/java/server/impl/tiffanybonzon/Server.java @@ -0,0 +1,184 @@ +package server.impl.tiffanybonzon; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Implementation of the multithreaded server. + * ***Strongly**** inspired by the Multi-Threaded TCP server example + * + * @author Tiffany Bonzon + */ +public class Server { + final static Logger LOG = Logger.getLogger(Server.class.getName()); + int port; + + /** + * Server Constructor + * @param port The port number on which the server listens + */ + public Server(int port) { + this.port = port; + } + + /** + * Initializes the process on a new thread and starts it + */ + public void serveClients() { + LOG.info("Starting the CalcServer Worker on a new thread..."); + new Thread(new CalcServerWorker()).start(); + } + + /** + * Listens for incoming connections and starts a new thread once a client connects + */ + private class CalcServerWorker implements Runnable { + public void run() { + ServerSocket ss; + + // Tries to create a socket binded to the specified port + try { + ss = new ServerSocket(port); + } catch(IOException e) { + LOG.log(Level.SEVERE, null, e); + return; + } + + while(true) { + LOG.log(Level.INFO, "Waiting for a new client on port {0}", port); + + try { + Socket cs = ss.accept(); + LOG.info("A new client has arrived. Starting a new thread and delegating work..."); + new Thread(new ServantWorker(cs)).start(); + } catch(IOException e) { + LOG.log(Level.SEVERE, null, e); + } + } + } + + /** + * Takes care of clients once they have connected. + * This is where we implement the application protocol logic + */ + private class ServantWorker implements Runnable { + Socket cs; + BufferedReader in = null; + PrintWriter out = null; + + public ServantWorker(Socket cs) { + try { + this.cs = cs; + in = new BufferedReader(new InputStreamReader(cs.getInputStream())); + out = new PrintWriter(cs.getOutputStream()); + } catch (IOException e) { + LOG.log(Level.SEVERE, null, e); + } + } + + public void run() { + String clientMessage; + boolean clientSentEND = false; + + try { + LOG.info("Reading until the client sends END..."); + while(!clientSentEND && (clientMessage = in.readLine()) != null) { + clientMessage = clientMessage.toUpperCase(); + + if(clientMessage.equals("HELLO")) { + out.println("> Available operations: ADD SUB MUL DIV POW"); + out.flush(); + } else if(clientMessage.equals("HELP")) { + out.println("> Syntax: Each element is separated by a space, decimal is specified with a dot. Connection can be closed by typing END"); + out.flush(); + } else if(clientMessage.startsWith("END")) { + clientSentEND = true; + } else { + out.println("> " + processCalc(clientMessage)); + out.flush(); + } + } + + LOG.info("Cleaning up resources..."); + cs.close(); + in.close(); + out.close(); + + } catch(IOException e) { + if(in != null) { + try { + in.close(); + } catch(IOException ein) { + LOG.log(Level.SEVERE, ein.getMessage(), ein); + } + } + + if(out != null) { + out.close(); + } + + if(cs != null) { + try { + cs.close(); + } catch(IOException ecs) { + LOG.log(Level.SEVERE, ecs.getMessage(), ecs); + } + } + } + } + + /** + * Calculates the result of the operation sent by the client + * @param message The operation sent by the client + * @return The result of the operation or the appropriate error message + */ + private String processCalc(String message) { + String[] op = message.split(" "); + double operand1, operand2, result; + String ret; + + if(op.length != 3) { + return "ERROR: Invalid syntax!"; + } + + try { + operand1 = Double.parseDouble(op[1]); + operand2 = Double.parseDouble(op[2]); + } catch(NumberFormatException e) { + return "ERROR: Invalid operands!"; + } + + switch(op[0]) { + case "ADD": + result = operand1 + operand2; + break; + case "SUB": + result = operand1 - operand2; + break; + case "MUL": + result = operand1 * operand2; + break; + case "DIV": + if(operand2 == 0) { + return "ERROR: Can't divide by 0!"; + } + result = operand1 / operand2; + break; + case "POW": + result = Math.pow(operand1, operand2); + break; + default: + return "ERROR: Unknown operation!"; + } + + return "Result: " + result; + } + } + } +} diff --git a/specs/tiffanybonzon/CalcServer/src/test/java/server/tests/tiffanybonzon/InitTest.java b/specs/tiffanybonzon/CalcServer/src/test/java/server/tests/tiffanybonzon/InitTest.java new file mode 100644 index 0000000..b54671a --- /dev/null +++ b/specs/tiffanybonzon/CalcServer/src/test/java/server/tests/tiffanybonzon/InitTest.java @@ -0,0 +1,12 @@ +package server.tests.tiffanybonzon; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class InitTest { + @Test + void theServerShouldSendOPListWhenReceivingHello() { + //Not sure how to test...will look into it later + } +} From 5157598b7507574afdbb73e075c277c7555a1f7c Mon Sep 17 00:00:00 2001 From: Tiffany Bonzon Date: Fri, 20 Mar 2020 22:25:20 +0100 Subject: [PATCH 3/6] Added Connection Tests + pass --- specs/tiffanybonzon/CalcServer/pom.xml | 11 ++- .../java/server/test/tiffanybonzon/Tests.java | 73 +++++++++++++++++++ .../server/tests/tiffanybonzon/InitTest.java | 12 --- 3 files changed, 78 insertions(+), 18 deletions(-) create mode 100644 specs/tiffanybonzon/CalcServer/src/test/java/server/test/tiffanybonzon/Tests.java delete mode 100644 specs/tiffanybonzon/CalcServer/src/test/java/server/tests/tiffanybonzon/InitTest.java diff --git a/specs/tiffanybonzon/CalcServer/pom.xml b/specs/tiffanybonzon/CalcServer/pom.xml index aa521ec..5bf7956 100644 --- a/specs/tiffanybonzon/CalcServer/pom.xml +++ b/specs/tiffanybonzon/CalcServer/pom.xml @@ -29,12 +29,6 @@ 5.4.0 test - - junit - junit - 4.12 - test - @@ -42,6 +36,7 @@ org.apache.maven.plugins maven-jar-plugin + 3.2.0 @@ -50,6 +45,10 @@ + + maven-surefire-plugin + 2.22.1 + diff --git a/specs/tiffanybonzon/CalcServer/src/test/java/server/test/tiffanybonzon/Tests.java b/specs/tiffanybonzon/CalcServer/src/test/java/server/test/tiffanybonzon/Tests.java new file mode 100644 index 0000000..1703e23 --- /dev/null +++ b/specs/tiffanybonzon/CalcServer/src/test/java/server/test/tiffanybonzon/Tests.java @@ -0,0 +1,73 @@ +package server.test.tiffanybonzon; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import server.impl.tiffanybonzon.Server; + +import java.io.IOException; +import java.net.Socket; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +public class Tests { + @BeforeAll + static void initServ() { + Server srv = new Server(2112); + srv.serveClients(); + } + + /***************************************** + * CONNECTION TESTS + *****************************************/ + @Test + void theServerShouldAcceptAConnection() { + Socket client = null; + + try { + client = new Socket("localhost", 2112); + assertTrue(client.isConnected()); + + } catch(IOException e) { + fail(); + } finally { + try { + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } + + @Test + void theServerShouldAcceptMultipleConnections() { + int clientNum = 5; + Socket[] clients = new Socket[clientNum]; + + try { + for(int i = 0; i < clientNum; ++i) { + clients[i] = new Socket("localhost", 2112); + } + + assertTrue(clients[0].isConnected() && clients[1].isConnected() && clients[2].isConnected() && clients[3].isConnected() && clients[4].isConnected()); + } catch(IOException e) { + fail(); + } finally { + try { + for(int i = 0; i < clientNum; ++i) { + clients[i].close(); + } + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } + + /***************************************** + * INIT TESTS + *****************************************/ + @Test + void theServerShouldSendOPListWhenReceivingHello() { + assertTrue(true); + } +} diff --git a/specs/tiffanybonzon/CalcServer/src/test/java/server/tests/tiffanybonzon/InitTest.java b/specs/tiffanybonzon/CalcServer/src/test/java/server/tests/tiffanybonzon/InitTest.java deleted file mode 100644 index b54671a..0000000 --- a/specs/tiffanybonzon/CalcServer/src/test/java/server/tests/tiffanybonzon/InitTest.java +++ /dev/null @@ -1,12 +0,0 @@ -package server.tests.tiffanybonzon; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class InitTest { - @Test - void theServerShouldSendOPListWhenReceivingHello() { - //Not sure how to test...will look into it later - } -} From 7b41065a1dae3a5b3f8fe47b61b7ccc0b024f06b Mon Sep 17 00:00:00 2001 From: Tiffany Bonzon Date: Fri, 20 Mar 2020 23:07:48 +0100 Subject: [PATCH 4/6] Pass Init tests --- .../java/server/test/tiffanybonzon/Tests.java | 67 +++++++++++++++++-- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/specs/tiffanybonzon/CalcServer/src/test/java/server/test/tiffanybonzon/Tests.java b/specs/tiffanybonzon/CalcServer/src/test/java/server/test/tiffanybonzon/Tests.java index 1703e23..c2991b9 100644 --- a/specs/tiffanybonzon/CalcServer/src/test/java/server/test/tiffanybonzon/Tests.java +++ b/specs/tiffanybonzon/CalcServer/src/test/java/server/test/tiffanybonzon/Tests.java @@ -4,11 +4,10 @@ import org.junit.jupiter.api.Test; import server.impl.tiffanybonzon.Server; -import java.io.IOException; +import java.io.*; import java.net.Socket; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.*; public class Tests { @BeforeAll @@ -68,6 +67,66 @@ void theServerShouldAcceptMultipleConnections() { *****************************************/ @Test void theServerShouldSendOPListWhenReceivingHello() { - assertTrue(true); + Socket client = null; + String expectedResponse = "> Available operations: ADD SUB MUL DIV POW"; + BufferedWriter clientRequest = null; + BufferedReader serverResponse = null; + + try { + client = new Socket("localhost", 2112); + clientRequest = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); + serverResponse = new BufferedReader(new InputStreamReader(client.getInputStream())); + + clientRequest.write("HELLO\n"); + clientRequest.flush(); + + assertEquals(expectedResponse, serverResponse.readLine()); + + } catch(IOException e) { + fail(); + } finally { + try { + clientRequest.close(); + serverResponse.close(); + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } + + @Test + void theServerShouldSendOPListWhenReceivingMultipleHello() { + Socket client = null; + String expectedResponse = "> Available operations: ADD SUB MUL DIV POW"; + BufferedWriter clientRequest = null; + BufferedReader serverResponse = null; + + try { + client = new Socket("localhost", 2112); + clientRequest = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); + serverResponse = new BufferedReader(new InputStreamReader(client.getInputStream())); + + clientRequest.write("HELLO\n"); + clientRequest.flush(); + if(serverResponse.readLine().equals(expectedResponse)) { + clientRequest.write("HELLO\n"); + clientRequest.flush(); + assertEquals(expectedResponse, serverResponse.readLine()); + } else { + fail(); + } + + } catch(IOException e) { + fail(); + } finally { + try { + clientRequest.close(); + serverResponse.close(); + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } } } From d9cf7e52088eb0d2ec7924b71693cd7c3022fa3f Mon Sep 17 00:00:00 2001 From: Tiffany Bonzon Date: Sun, 22 Mar 2020 21:28:40 +0100 Subject: [PATCH 5/6] Pass all tests --- .../server/impl/tiffanybonzon/Server.java | 5 +- .../java/server/test/tiffanybonzon/Tests.java | 430 ++++++++++++++++++ 2 files changed, 434 insertions(+), 1 deletion(-) diff --git a/specs/tiffanybonzon/CalcServer/src/main/java/server/impl/tiffanybonzon/Server.java b/specs/tiffanybonzon/CalcServer/src/main/java/server/impl/tiffanybonzon/Server.java index cdfab22..bfebcc4 100644 --- a/specs/tiffanybonzon/CalcServer/src/main/java/server/impl/tiffanybonzon/Server.java +++ b/specs/tiffanybonzon/CalcServer/src/main/java/server/impl/tiffanybonzon/Server.java @@ -99,9 +99,12 @@ public void run() { out.flush(); } else if(clientMessage.startsWith("END")) { clientSentEND = true; - } else { + } else if(clientMessage.startsWith("ADD") || clientMessage.startsWith("SUB") || clientMessage.startsWith("MUL") || clientMessage.startsWith("DIV") || clientMessage.startsWith("POW")) { out.println("> " + processCalc(clientMessage)); out.flush(); + } else { + out.println("> ERROR: Unknown command!"); + out.flush(); } } diff --git a/specs/tiffanybonzon/CalcServer/src/test/java/server/test/tiffanybonzon/Tests.java b/specs/tiffanybonzon/CalcServer/src/test/java/server/test/tiffanybonzon/Tests.java index c2991b9..76a55ce 100644 --- a/specs/tiffanybonzon/CalcServer/src/test/java/server/test/tiffanybonzon/Tests.java +++ b/specs/tiffanybonzon/CalcServer/src/test/java/server/test/tiffanybonzon/Tests.java @@ -49,6 +49,7 @@ void theServerShouldAcceptMultipleConnections() { } assertTrue(clients[0].isConnected() && clients[1].isConnected() && clients[2].isConnected() && clients[3].isConnected() && clients[4].isConnected()); + } catch(IOException e) { fail(); } finally { @@ -129,4 +130,433 @@ void theServerShouldSendOPListWhenReceivingMultipleHello() { } } } + + /***************************************** + * COMMANDS TESTS + *****************************************/ + @Test + void theServerShouldRespondToTheHelpCommand() { + Socket client = null; + String expectedResponse = "> Syntax: Each element is separated by a space, decimal is specified with a dot. Connection can be closed by typing END"; + BufferedWriter clientRequest = null; + BufferedReader serverResponse = null; + + try { + client = new Socket("localhost", 2112); + clientRequest = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); + serverResponse = new BufferedReader(new InputStreamReader(client.getInputStream())); + + clientRequest.write("HELP\n"); + clientRequest.flush(); + + assertEquals(expectedResponse, serverResponse.readLine()); + + } catch(IOException e) { + fail(); + } finally { + try { + clientRequest.close(); + serverResponse.close(); + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } + + @Test + void theServerShouldNotAnswerToEndCommand() { + Socket client = null; + String expectedResponse = "> Syntax: Each element is separated by a space, decimal is specified with a dot. Connection can be closed by typing END"; + BufferedWriter clientRequest = null; + BufferedReader serverResponse = null; + + try { + client = new Socket("localhost", 2112); + clientRequest = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); + serverResponse = new BufferedReader(new InputStreamReader(client.getInputStream())); + + clientRequest.write("END\n"); + clientRequest.flush(); + + assertNull(serverResponse.readLine()); + + } catch(IOException e) { + fail(); + } finally { + try { + clientRequest.close(); + serverResponse.close(); + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } + + @Test + void theServerShouldSendAnErrorWhenReceivingAnUnknownCommand() { + Socket client = null; + String expectedResponse = "> ERROR: Unknown command!"; + BufferedWriter clientRequest = null; + BufferedReader serverResponse = null; + + try { + client = new Socket("localhost", 2112); + clientRequest = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); + serverResponse = new BufferedReader(new InputStreamReader(client.getInputStream())); + + clientRequest.write("HALLO\n"); + clientRequest.flush(); + + assertEquals(expectedResponse, serverResponse.readLine()); + + } catch(IOException e) { + fail(); + } finally { + try { + clientRequest.close(); + serverResponse.close(); + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } + + /***************************************** + * OPERATIONS TESTS + *****************************************/ + @Test + void theServerCanAddTwoIntergers() { + Socket client = null; + String expectedResponse = "> Result: 5.0"; + BufferedWriter clientRequest = null; + BufferedReader serverResponse = null; + + try { + client = new Socket("localhost", 2112); + clientRequest = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); + serverResponse = new BufferedReader(new InputStreamReader(client.getInputStream())); + + clientRequest.write("ADD 2 3\n"); + clientRequest.flush(); + + assertEquals(expectedResponse, serverResponse.readLine()); + + } catch(IOException e) { + fail(); + } finally { + try { + clientRequest.close(); + serverResponse.close(); + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } + + @Test + void theServerCanAddTwoFloats() { + Socket client = null; + String expectedResponse = "> Result: 7.321"; + BufferedWriter clientRequest = null; + BufferedReader serverResponse = null; + + try { + client = new Socket("localhost", 2112); + clientRequest = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); + serverResponse = new BufferedReader(new InputStreamReader(client.getInputStream())); + + clientRequest.write("ADD 3.3 4.021\n"); + clientRequest.flush(); + + assertEquals(expectedResponse, serverResponse.readLine()); + + } catch(IOException e) { + fail(); + } finally { + try { + clientRequest.close(); + serverResponse.close(); + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } + + @Test + void theServerCanAddNegativeNumbers() { + Socket client = null; + String expectedResponse = "> Result: -2.4"; + BufferedWriter clientRequest = null; + BufferedReader serverResponse = null; + + try { + client = new Socket("localhost", 2112); + clientRequest = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); + serverResponse = new BufferedReader(new InputStreamReader(client.getInputStream())); + + clientRequest.write("ADD -1.2 -1.2\n"); + clientRequest.flush(); + + assertEquals(expectedResponse, serverResponse.readLine()); + + } catch(IOException e) { + fail(); + } finally { + try { + clientRequest.close(); + serverResponse.close(); + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } + + @Test + void theServerCanSubstractTwoNumbers() { + Socket client = null; + String expectedResponse = "> Result: 3.9"; + BufferedWriter clientRequest = null; + BufferedReader serverResponse = null; + + try { + client = new Socket("localhost", 2112); + clientRequest = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); + serverResponse = new BufferedReader(new InputStreamReader(client.getInputStream())); + + clientRequest.write("SUB 7 3.1\n"); + clientRequest.flush(); + + assertEquals(expectedResponse, serverResponse.readLine()); + + } catch(IOException e) { + fail(); + } finally { + try { + clientRequest.close(); + serverResponse.close(); + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } + + @Test + void theServerCanMulitplyTwoNumbers() { + Socket client = null; + String expectedResponse = "> Result: 15.0"; + BufferedWriter clientRequest = null; + BufferedReader serverResponse = null; + + try { + client = new Socket("localhost", 2112); + clientRequest = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); + serverResponse = new BufferedReader(new InputStreamReader(client.getInputStream())); + + clientRequest.write("MUL 5 3\n"); + clientRequest.flush(); + + assertEquals(expectedResponse, serverResponse.readLine()); + + } catch(IOException e) { + fail(); + } finally { + try { + clientRequest.close(); + serverResponse.close(); + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } + + @Test + void theServerCanDivideTwoNumbers() { + Socket client = null; + String expectedResponse = "> Result: 5.0"; + BufferedWriter clientRequest = null; + BufferedReader serverResponse = null; + + try { + client = new Socket("localhost", 2112); + clientRequest = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); + serverResponse = new BufferedReader(new InputStreamReader(client.getInputStream())); + + clientRequest.write("DIV 15 3\n"); + clientRequest.flush(); + + assertEquals(expectedResponse, serverResponse.readLine()); + + } catch(IOException e) { + fail(); + } finally { + try { + clientRequest.close(); + serverResponse.close(); + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } + + @Test + void theServerCanExponentiateTwoNumbers() { + Socket client = null; + String expectedResponse = "> Result: 27.0"; + BufferedWriter clientRequest = null; + BufferedReader serverResponse = null; + + try { + client = new Socket("localhost", 2112); + clientRequest = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); + serverResponse = new BufferedReader(new InputStreamReader(client.getInputStream())); + + clientRequest.write("POW 3 3\n"); + clientRequest.flush(); + + assertEquals(expectedResponse, serverResponse.readLine()); + + } catch(IOException e) { + fail(); + } finally { + try { + clientRequest.close(); + serverResponse.close(); + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } + + /***************************************** + * INVALID OPERATIONS TESTS + *****************************************/ + @Test + void theServerSendsErrorWhenOperationIsNotCorrectlyFormatted() { + Socket client = null; + String expectedResponse = "> ERROR: Invalid syntax!"; + BufferedWriter clientRequest = null; + BufferedReader serverResponse = null; + + try { + client = new Socket("localhost", 2112); + clientRequest = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); + serverResponse = new BufferedReader(new InputStreamReader(client.getInputStream())); + + clientRequest.write("ADD 3 3 3\n"); + clientRequest.flush(); + + assertEquals(expectedResponse, serverResponse.readLine()); + + } catch(IOException e) { + fail(); + } finally { + try { + clientRequest.close(); + serverResponse.close(); + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } + + @Test + void theServerSendsErrorWhenOperandsAreIncorrectlyFormatted() { + Socket client = null; + String expectedResponse = "> ERROR: Invalid operands!"; + BufferedWriter clientRequest = null; + BufferedReader serverResponse = null; + + try { + client = new Socket("localhost", 2112); + clientRequest = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); + serverResponse = new BufferedReader(new InputStreamReader(client.getInputStream())); + + clientRequest.write("ADD 3 3a\n"); + clientRequest.flush(); + + assertEquals(expectedResponse, serverResponse.readLine()); + + } catch(IOException e) { + fail(); + } finally { + try { + clientRequest.close(); + serverResponse.close(); + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } + + @Test + void theServerShouldSendErrorWhenTheClientWantsTODivideByZero() { + Socket client = null; + String expectedResponse = "> ERROR: Can't divide by 0!"; + BufferedWriter clientRequest = null; + BufferedReader serverResponse = null; + + try { + client = new Socket("localhost", 2112); + clientRequest = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); + serverResponse = new BufferedReader(new InputStreamReader(client.getInputStream())); + + clientRequest.write("DIV 79 0\n"); + clientRequest.flush(); + + assertEquals(expectedResponse, serverResponse.readLine()); + + } catch(IOException e) { + fail(); + } finally { + try { + clientRequest.close(); + serverResponse.close(); + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } + + @Test + void theServerSendsErrorWhenOperationsAreIncorrectlyFormatted() { + Socket client = null; + String expectedResponse = "> ERROR: Unknown operation!"; + BufferedWriter clientRequest = null; + BufferedReader serverResponse = null; + + try { + client = new Socket("localhost", 2112); + clientRequest = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); + serverResponse = new BufferedReader(new InputStreamReader(client.getInputStream())); + + clientRequest.write("ADDE 3 3\n"); + clientRequest.flush(); + + assertEquals(expectedResponse, serverResponse.readLine()); + + } catch(IOException e) { + fail(); + } finally { + try { + clientRequest.close(); + serverResponse.close(); + client.close(); + } catch(Exception e1) { + System.out.println(e1.getMessage()); + } + } + } } From ee54be2c353ca89908686192c48ee273568c1126 Mon Sep 17 00:00:00 2001 From: Tiffany Bonzon Date: Sun, 22 Mar 2020 21:38:33 +0100 Subject: [PATCH 6/6] Protocol updated to match server --- specs/tiffanybonzon/PROTOCOL.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/specs/tiffanybonzon/PROTOCOL.md b/specs/tiffanybonzon/PROTOCOL.md index 870373d..c492d71 100644 --- a/specs/tiffanybonzon/PROTOCOL.md +++ b/specs/tiffanybonzon/PROTOCOL.md @@ -9,11 +9,11 @@ The server can be reached by its IP address (127.0.0.1 if server and clients are The client initiates the exchange ## What is the sequence of messages exchanged by the client and the server? (flow) -1. Client initializes connection ("Hello") -2. Servers answers with operation list ("OP : ADD SUB MULT DIV POW") +1. Client initializes connection ("HELLO") +2. Servers answers with operation list ("OP : ADD SUB MUL DIV POW") 3. Client answers ("OP NUM1 NUM2") 4. Server sends answer -5. Server waits for next operation ("OP NUM1 NUM") or for client to end the session ("END") or times out after 60 seconds +5. Server waits for next operation ("OP NUM1 NUM") or for client to end the session ("END") ## What happens when a message is received from the other party? (semantics) The server processes the requests @@ -25,9 +25,8 @@ The client displays the answers "Available operations: ADD SUB MULT DIV POW. Syntax: (Each element is separated by a space, decimal is specified with a dot)" 3. Client replies: "OP NUM1 NUM2" -4. Server return calc answer: "" or "Syntax Error / Operation unknown" +4. Server return calc answer: "" or "ERROR: Syntax Error / Operation Unknown / Command Unknown" 5. Client sends new calc or ends the session: "OP NUM1 NUM2" or "END" ## Who closes the connection and when? The clients can tell the server to close the connection by sending "END" -The server automatically closes the connection after 60 seconds of inactivity