diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index 5dbfe4bb..5ee2bc6f 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -7,16 +7,10 @@ import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.stage.Stage; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import seng302.gameServer.ServerAdvertiser; -import seng302.model.PolarTable; -import seng302.visualiser.ServerListener; import java.io.IOException; @@ -87,6 +81,13 @@ public class App extends Application { // ClientPacketParser.appClose(); // ClientPacketParser.appClose(); + + try { + ServerAdvertiser.getInstance().unregister(); + } catch (IOException e1) { + logger.warn("Could not un-register game"); + } + System.exit(0); }); diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index 0b36ab16..ebe4abbe 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -1,37 +1,22 @@ package seng302.gameServer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; import javafx.scene.paint.Color; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.InputSource; -import seng302.gameServer.messages.BoatAction; -import seng302.gameServer.messages.BoatStatus; -import seng302.gameServer.messages.CustomizeRequestType; -import seng302.gameServer.messages.MarkRoundingMessage; -import seng302.gameServer.messages.MarkType; -import seng302.gameServer.messages.Message; -import seng302.gameServer.messages.RoundingBoatStatus; -import seng302.gameServer.messages.YachtEventCodeMessage; -import seng302.model.GeoPoint; -import seng302.model.Limit; -import seng302.model.Player; -import seng302.model.PolarTable; -import seng302.model.ServerYacht; +import seng302.gameServer.messages.*; +import seng302.model.*; import seng302.model.mark.CompoundMark; import seng302.model.mark.Mark; import seng302.model.mark.MarkOrder; import seng302.utilities.GeoUtility; import seng302.utilities.XMLParser; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.util.*; + /** * A Static class to hold information about the current state of the game (model) * Also contains logic for updating itself on regular time intervals on its own thread @@ -699,4 +684,11 @@ public class GameState implements Runnable { public static void resetCustomizationFlag() { customizationFlag = false; } + + public static Integer getSpacesLeft(){ + Integer numberOfPlayers = GameState.getPlayers().size(); + Integer maxPlayers = GameState.MAX_PLAYERS; + + return maxPlayers - numberOfPlayers - 1; + } } diff --git a/src/main/java/seng302/gameServer/MainServerThread.java b/src/main/java/seng302/gameServer/MainServerThread.java index d1e5a23a..0aa4b3a6 100644 --- a/src/main/java/seng302/gameServer/MainServerThread.java +++ b/src/main/java/seng302/gameServer/MainServerThread.java @@ -1,17 +1,26 @@ package seng302.gameServer; -import javafx.application.Platform; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; import seng302.gameServer.messages.*; import seng302.model.GeoPoint; import seng302.model.Player; import seng302.model.PolarTable; import seng302.model.ServerYacht; import seng302.model.mark.CompoundMark; +import seng302.model.stream.xml.parser.RegattaXMLData; import seng302.utilities.GeoUtility; +import seng302.utilities.XMLGenerator; +import seng302.utilities.XMLParser; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; +import java.io.StringReader; import java.net.ServerSocket; import java.time.LocalDateTime; import java.util.*; @@ -42,6 +51,41 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { private ArrayList serverToClientThreads = new ArrayList<>(); private Logger logger = LoggerFactory.getLogger(MainServerThread.class); + private void startAdvertisingServer(){ + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db; + Document doc; + XMLGenerator generator = new XMLGenerator(); + + try { + db = dbf.newDocumentBuilder(); + String regatta = generator.getRegattaAsXml(); + StringReader stringReader = new StringReader(regatta); + InputSource is = new InputSource(stringReader); + doc = db.parse(is); + } catch (ParserConfigurationException | IOException | SAXException e) { + logger.warn("Couldn't load race regatta"); + return; + } + + RegattaXMLData regattaXMLData = XMLParser.parseRegatta(doc); + + Integer spacesLeft = GameState.getSpacesLeft(); + + // No spaces left on server + if (spacesLeft < 1){ + return; + } + + // Start advertising server + try{ + ServerAdvertiser.getInstance().setMapName(regattaXMLData.getCourseName()).setSpacesLeft(spacesLeft); + ServerAdvertiser.getInstance().registerGame(PORT, regattaXMLData.getRegattaName()); + } catch (IOException e) { + logger.warn("Could not register server"); + } + } + public MainServerThread() { new GameState("localhost"); try { @@ -50,13 +94,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { serverLog("IO error in server thread handler upon trying to make new server socket", 0); } - // Start advertising server - try{ - ServerAdvertiser.getInstance().registerGame(PORT, "PP Test Server", 10, "Random Map"); - } catch (IOException e) { - logger.warn("Could not register server"); - } - + startAdvertisingServer(); PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv")); GameState.addMarkPassListener(this::broadcastMessage); @@ -189,6 +227,12 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { } }); serverToClientThread.addDisconnectListener(this::clientDisconnected); + + try { + ServerAdvertiser.getInstance().setSpacesLeft(GameState.getSpacesLeft()); + } catch (IOException e) { + logger.warn("Couldn't update advertisement"); + } } /** @@ -215,6 +259,13 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { } } serverToClientThreads.remove(closedConnection); + + try { + ServerAdvertiser.getInstance().setSpacesLeft(GameState.getSpacesLeft()); + } catch (IOException e) { + logger.warn("Couldn't update advertisement"); + } + closedConnection.terminate(); } @@ -222,7 +273,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { try { ServerAdvertiser.getInstance().unregister(); } catch (IOException e) { - logger.warn("Error unregistering server"); + logger.warn("Error unregistered server"); } initialiseBoatPositions(); diff --git a/src/main/java/seng302/gameServer/ServerAdvertiser.java b/src/main/java/seng302/gameServer/ServerAdvertiser.java index 2d069372..6b5f07da 100644 --- a/src/main/java/seng302/gameServer/ServerAdvertiser.java +++ b/src/main/java/seng302/gameServer/ServerAdvertiser.java @@ -6,20 +6,45 @@ import java.io.IOException; import java.net.InetAddress; import java.util.Hashtable; +/** + * Advertises the game server on the local network + */ public class ServerAdvertiser { + /* + Our service name & protocol + + This must be in the format _Service._Proto.Name as per http://www.ietf.org/rfc/rfc2782.txt + Where Service is unique on the network, and protocol is usually _tcp. + + The pseudo-domain 'local.' must end in a full-stop. This is used to indicate that + the lookup should be performed using an IP multicast query on the local IP network. + + Read this before changing any of the following values + https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/NetServices/Articles/domainnames.html#//apple_ref/doc/uid/TP40002460-SW1 + */ private static String SERVICE = "_partyatsea"; private static String PROTOCOL = "_tcp"; public static String SERVICE_TYPE = SERVICE + "." + PROTOCOL + ".local."; - private static Integer PROTO_VERSION = 1; - private static ServerAdvertiser instance = null; private static JmDNS jmdnsInstance = null; + private ServiceInfo serviceInfo; // Note: Whenever this is changed, our service will be re-registered on the network. + + private Hashtable props; private ServerAdvertiser() throws IOException{ jmdnsInstance = JmDNS.create(InetAddress.getLocalHost()); + + props = new Hashtable<>(); + props.put("map", ""); + props.put("spacesLeft", "0"); } + /** + * Get an instance of the ServerAdvertiser, create an instance if there isn't already one + * @return A ServerAdvertiser Instance + * @throws IOException If there was an exception creating the instance + */ public static ServerAdvertiser getInstance() throws IOException { if (instance == null){ instance = new ServerAdvertiser(); @@ -28,13 +53,47 @@ public class ServerAdvertiser { return instance; } - public void registerGame(Integer portNo, String serverName, Integer spacesLeft, String mapName) { - Hashtable props = new Hashtable<>(); + /** + * Set the map name & broadcast an update on the network + * @param mapName The new map name + * @return The current ServerAdvertiser instance + */ + public ServerAdvertiser setMapName(String mapName){ + props.replace("map", mapName); - props.put("map", mapName); - props.put("spacesLeft", spacesLeft.toString()); + if (serviceInfo != null){ + serviceInfo.setText(props); + } - ServiceInfo serviceInfo = ServiceInfo.create(SERVICE_TYPE, serverName, portNo, 0, 0, props); + return instance; + } + + /** + * Set the spaces left on the server & broadcast an update on the network + * @param spacesLeft The number of spaces left on the server + * @return The current ServerAdvertiser instance + */ + public ServerAdvertiser setSpacesLeft(Integer spacesLeft){ + props.replace("spacesLeft", spacesLeft.toString()); + + if (serviceInfo != null){ + serviceInfo.setText(props); + } + + return instance; + } + + /** + * Register this service on the network + * + * Note: other parameters (map name/spaces left etc) are set after the + * service has been registered + * @param portNo The servers port number + * @param serverName The servers name + */ + public void registerGame(Integer portNo, String serverName) { + + serviceInfo = ServiceInfo.create(SERVICE_TYPE, serverName, portNo, 0, 0, props); new java.util.Timer().schedule( new java.util.TimerTask() { @@ -46,12 +105,14 @@ public class ServerAdvertiser { System.out.println("Failed"); } } - }, 0 - ); + }, 0); } + /** + * Unregister the service + */ public void unregister(){ - jmdnsInstance.unregisterAllServices(); - jmdnsInstance = null; + if (serviceInfo != null) + jmdnsInstance.unregisterService(serviceInfo); } } diff --git a/src/main/java/seng302/gameServer/ServerDescription.java b/src/main/java/seng302/gameServer/ServerDescription.java index 181cde39..02440382 100644 --- a/src/main/java/seng302/gameServer/ServerDescription.java +++ b/src/main/java/seng302/gameServer/ServerDescription.java @@ -3,7 +3,6 @@ package seng302.gameServer; public class ServerDescription { private String address; private Integer portNum; - private String serverName; private String mapName; private Integer spacesLeft; @@ -36,4 +35,39 @@ public class ServerDescription { public Integer spacesLeft() { return spacesLeft; } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!ServerDescription.class.isAssignableFrom(obj.getClass())) { + return false; + } + final ServerDescription other = (ServerDescription) obj; + + if (!this.getAddress().equals(other.getAddress()) ) { + return false; + } + + if (!this.portNumber().equals(other.portNumber())){ + return false; + } + + if (!this.getMapName().equals(other.getMapName())){ + return false; + } + + if (!this.getName().equals(other.getName())){ + return false; + } + + return true; + } + + @Override + public int hashCode() { + return this.getName().hashCode() + this.getAddress().hashCode() + + this.portNumber().hashCode() + this.getMapName().hashCode(); + } } diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java index 3a9b4057..82e481ce 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -1,59 +1,24 @@ package seng302.gameServer; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import seng302.gameServer.messages.*; +import seng302.model.Player; +import seng302.model.ServerYacht; +import seng302.model.stream.packets.PacketType; +import seng302.model.stream.packets.StreamPacket; +import seng302.model.stream.xml.generator.Race; +import seng302.utilities.XMLGenerator; + +import java.io.*; import java.net.Socket; import java.net.SocketException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Observable; -import java.util.Observer; +import java.util.*; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; import java.util.zip.CRC32; import java.util.zip.Checksum; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import seng302.gameServer.messages.BoatAction; -import seng302.gameServer.messages.BoatLocationMessage; -import seng302.gameServer.messages.ClientType; -import seng302.gameServer.messages.CustomizeRequestType; -import seng302.gameServer.messages.Message; -import seng302.gameServer.messages.RegistrationResponseMessage; -import seng302.gameServer.messages.RegistrationResponseStatus; -import seng302.gameServer.messages.XMLMessage; -import seng302.gameServer.messages.XMLMessageSubType; -import seng302.gameServer.messages.YachtEventCodeMessage; -import seng302.gameServer.messages.YachtEventCodeMessage; -import seng302.model.Player; -import seng302.model.ServerYacht; -import seng302.model.stream.packets.PacketType; -import seng302.model.stream.packets.StreamPacket; -import seng302.model.stream.xml.generator.Race; -import seng302.model.stream.xml.generator.Regatta; -import seng302.utilities.XMLGenerator; -import seng302.gameServer.messages.BoatAction; -import seng302.gameServer.messages.BoatLocationMessage; -import seng302.gameServer.messages.ClientType; -import seng302.gameServer.messages.Message; -import seng302.gameServer.messages.RegistrationResponseMessage; -import seng302.gameServer.messages.RegistrationResponseStatus; -import seng302.gameServer.messages.XMLMessage; -import seng302.gameServer.messages.XMLMessageSubType; -import seng302.gameServer.messages.YachtEventCodeMessage; -import seng302.model.Player; -import seng302.model.ServerYacht; -import seng302.model.stream.packets.PacketType; -import seng302.model.stream.packets.StreamPacket; -import seng302.model.stream.xml.generator.Race; -import seng302.model.stream.xml.generator.Regatta; -import seng302.utilities.XMLGenerator; /** * A class describing a single connection to a Client for the purposes of sending and receiving on @@ -258,12 +223,6 @@ public class ServerToClientThread implements Runnable, Observer { race.addBoat(yacht); } - //@TODO calculate lat/lng values - xml.setRegatta( - new Regatta( - "Party Parrot Test Server", "Bermuda Test Course", - 57.6679590, 11.8503233) - ); xml.setRace(race); XMLMessage xmlMessage; diff --git a/src/main/java/seng302/utilities/XMLGenerator.java b/src/main/java/seng302/utilities/XMLGenerator.java index 7fcc8efd..6c478af2 100644 --- a/src/main/java/seng302/utilities/XMLGenerator.java +++ b/src/main/java/seng302/utilities/XMLGenerator.java @@ -3,13 +3,15 @@ package seng302.utilities; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; +import seng302.gameServer.messages.XMLMessageSubType; +import seng302.model.stream.xml.generator.Race; +import seng302.model.stream.xml.generator.Regatta; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; -import seng302.model.stream.xml.generator.Race; -import seng302.model.stream.xml.generator.Regatta; -import seng302.gameServer.messages.XMLMessageSubType; +import java.util.Random; /** * An XML generator to generate the Race, Boat, and Regatta XML dynamically @@ -20,9 +22,14 @@ public class XMLGenerator { private static final String BOATS_TEMPLATE_NAME = "boats.ftlh"; private static final String RACE_TEMPLATE_NAME = "race.ftlh"; private Configuration configuration; - private Regatta regatta; + private Regatta regatta = null; private Race race; + public static Regatta DEFAULT_REGATTA = new Regatta("Party Parrot Test Server " + new Random().nextInt(100), + "Bermuda Test Course", + 57.6679590, + 11.8503233); + /** * Set up a configuration instance for Apache Freemake */ @@ -106,7 +113,7 @@ public class XMLGenerator { public String getRegattaAsXml(){ String result = null; - if (regatta == null) return null; + if (regatta == null) regatta = DEFAULT_REGATTA; try { result = parseToXmlString(REGATTA_TEMPLATE_NAME, XMLMessageSubType.REGATTA); diff --git a/src/main/java/seng302/visualiser/ServerListener.java b/src/main/java/seng302/visualiser/ServerListener.java index 2cb79bdb..c9614cf7 100644 --- a/src/main/java/seng302/visualiser/ServerListener.java +++ b/src/main/java/seng302/visualiser/ServerListener.java @@ -8,12 +8,13 @@ import javax.jmdns.ServiceEvent; import javax.jmdns.ServiceListener; import java.io.IOException; import java.net.InetAddress; -import java.net.UnknownHostException; import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.HashSet; +import java.util.Set; +/** + * Listens for servers on the local network + */ public class ServerListener{ private static ServerListener instance; private ServerListenerDelegate delegate; @@ -21,35 +22,51 @@ public class ServerListener{ GameServeMonitor listener; private class GameServeMonitor implements ServiceListener { - private List servers; + private Set servers; GameServeMonitor(){ - servers = new ArrayList<>(); + servers = new HashSet<>(); } + /** + * A Service has been detected but not resolved + * @param event The ServiceEvent + */ @Override public void serviceAdded(ServiceEvent event) { } + /** + * A Service has been removed / unregistered + * @param event The ServiceEvent + */ @Override public void serviceRemoved(ServiceEvent event) { - Integer serverId = -1; + String serverName = event.getInfo().getName(); - for (int i = 0; i < servers.size(); i++){ - ServerDescription server = servers.get(i); - if (server.getName().equals(event.getInfo().getName())){ - serverId = i; - break; + ServerDescription toRemove = null; + + for (ServerDescription server : servers){ + if (server.getName().equals(serverName)){ + toRemove = server; } } - if (serverId > 0){ - servers.remove(serverId); + if (toRemove != null){ + servers.remove(toRemove); } - delegate.serverRemoved(servers); + delegate.serverRemoved(new ArrayList(servers)); + + // Get all other servers with the same name to respond if they are up + jmdns.requestServiceInfo(ServerAdvertiser.SERVICE_TYPE, serverName); + } + /** + * A Service has been added and resolved + * @param event The ServiceEvent + */ @Override public void serviceResolved(ServiceEvent event) { String address = event.getInfo().getServer(); @@ -60,9 +77,11 @@ public class ServerListener{ Integer spacesLeft = Integer.parseInt(event.getInfo().getPropertyString("spacesLeft")); ServerDescription serverDescription = new ServerDescription(serverName, mapName, spacesLeft, address, portNum); + + servers.remove(serverDescription); servers.add(serverDescription); - delegate.serverDetected(serverDescription, Collections.unmodifiableList(servers)); + delegate.serverDetected(serverDescription, new ArrayList(servers)); } } @@ -80,6 +99,10 @@ public class ServerListener{ return instance; } + /** + * Set the delegate to handle events + * @param delegate . + */ public void setDelegate(ServerListenerDelegate delegate){ this.delegate = delegate; } diff --git a/src/main/java/seng302/visualiser/controllers/StartScreenController.java b/src/main/java/seng302/visualiser/controllers/StartScreenController.java index 7d30f493..3b3d7c68 100644 --- a/src/main/java/seng302/visualiser/controllers/StartScreenController.java +++ b/src/main/java/seng302/visualiser/controllers/StartScreenController.java @@ -1,14 +1,6 @@ package seng302.visualiser.controllers; -import java.io.IOException; -import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.URL; -import java.util.*; - -import com.sun.security.ntlm.Server; -import cucumber.api.java.en.But; +import javafx.application.Platform; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.Alert; @@ -17,12 +9,20 @@ import javafx.scene.control.ListView; import javafx.scene.control.TextField; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.GridPane; -import seng302.gameServer.GameState; import seng302.gameServer.ServerDescription; import seng302.visualiser.GameClient; import seng302.visualiser.ServerListener; import seng302.visualiser.ServerListenerDelegate; +import java.io.IOException; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.URL; +import java.util.Enumeration; +import java.util.List; +import java.util.ResourceBundle; + /** * A Class describing the actions of the start screen controller * Created by wmu16 on 10/07/17. @@ -192,6 +192,10 @@ public class StartScreenController implements Initializable, ServerListenerDeleg return ipAddress; } + /** + * Update the server list with new information + * @param servers The current list of servers + */ private void refreshServerList(List servers){ this.serverList.getItems().clear(); @@ -204,20 +208,20 @@ public class StartScreenController implements Initializable, ServerListenerDeleg public void serverRemoved(List currentServers) { this.servers = currentServers; - refreshServerList(currentServers); + Platform.runLater(() -> refreshServerList(currentServers)); } @Override public void serverDetected(ServerDescription serverDescription, List servers) { this.servers = servers; - refreshServerList(servers); + Platform.runLater(() -> refreshServerList(servers)); } private void joinLobbyClicked() { Integer selectedServer = serverList.getSelectionModel().getSelectedIndex(); - if (this.servers == null || selectedServer >= this.servers.size()){ + if (this.servers == null || selectedServer >= this.servers.size() || selectedServer < 0){ Alert alert = new Alert(Alert.AlertType.ERROR, "Invalid server selected"); alert.showAndWait(); return; diff --git a/src/test/java/seng302/gameServer/server/TestServerDesc.java b/src/test/java/seng302/gameServer/server/TestServerDesc.java new file mode 100644 index 00000000..8ee50255 --- /dev/null +++ b/src/test/java/seng302/gameServer/server/TestServerDesc.java @@ -0,0 +1,48 @@ +package seng302.gameServer.server; + +import org.junit.Test; +import seng302.gameServer.ServerDescription; + +import static org.junit.Assert.assertTrue; + +public class TestServerDesc { + @Test + public void testEquals(){ + ServerDescription one = new ServerDescription("a", "b", 10, "asd", 1234); + ServerDescription two = new ServerDescription("a", "b", 10, "asd", 1234); + + assertTrue(one.equals(two)); + } + + @Test + public void testNotEqualName(){ + ServerDescription one = new ServerDescription("a", "b", 10, "asd", 1234); + ServerDescription two = new ServerDescription("a2", "b", 10, "asd", 1234); + + assertTrue(!one.equals(two)); + } + + @Test + public void testNotEqualMap(){ + ServerDescription one = new ServerDescription("a", "b", 10, "asd", 1234); + ServerDescription two = new ServerDescription("a", "ba", 10, "asd", 1234); + + assertTrue(!one.equals(two)); + } + + @Test + public void testNotEqualPort(){ + ServerDescription one = new ServerDescription("a", "b", 10, "asd", 1234); + ServerDescription two = new ServerDescription("a", "b", 10, "asd", 12341); + + assertTrue(!one.equals(two)); + } + + @Test + public void testNotEqualAddress(){ + ServerDescription one = new ServerDescription("a", "b", 10, "as1d", 1234); + ServerDescription two = new ServerDescription("a", "b", 10, "asd", 1234); + + assertTrue(!one.equals(two)); + } +}