Java Chat Server (Socket) - how to write unit test? - java

I have written a Java Chat Server program.
This is a simple standalone program for Server.
I have to run this then run Client to get Chat working.
What are some possible Unit Test scenarios for the server program? Can anyone show me some example of unit test based on this code?
I have never written a unit test code before and I can't really think of what needs to be tested here.. I think testing Connection can be one but what else? (and how to?)
public class SimpleChatServer {
static final Logger logger = LogManager.getLogger(SimpleChatServer.class);
ArrayList<PrintWriter> clientOutputStreams;
private BufferedReader reader;
private Socket sock;
private ServerSocket serverSock;
public class ClientHandler implements Runnable{
public ClientHandler(Socket clientSocket){ // Socket Connection
try {
sock = clientSocket;
InputStreamReader isReader = new InputStreamReader(sock.getInputStream());
reader = new BufferedReader(isReader);
} catch(Exception ex) {
logger.trace(ex);
}
}
public void run() {
String message;
try {
while ((message = reader.readLine()) != null) {
System.out.println("read " + message);
tellEveryone(message);
}
} catch(Exception ex) {
logger.trace(ex);
}
} //close run
} //close ClientHandler
public static void main (String[] args) throws Exception
{
new SimpleChatServer().listen();
}
#SuppressWarnings("resource")
public void listen()
{
clientOutputStreams = new ArrayList<PrintWriter>();
try {
ServerSocket serverSock = new ServerSocket(8000); //port number 8000 was used
while(true) {
Socket clientSocket = serverSock.accept();
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream());
clientOutputStreams.add(writer);
Thread t = new Thread(new ClientHandler(clientSocket));
t.start();
}
} catch (Exception ex) {
logger.trace("Server Error", ex);
} finally {
try
{
serverSock.close();
}
catch(Exception e){}
}
} // close go
public void tellEveryone(String message)
{
Iterator<PrintWriter> it = clientOutputStreams.iterator();
while(it.hasNext()) {
try {
PrintWriter writer = (PrintWriter) it.next();
writer.println(message);
writer.flush();
} catch (Exception ex) {
logger.trace(ex);
}
} // end while
} // close tellEveryone
}

I was going to crib an answer from Pragmatic Unit Testing, but suggest you just find a copy. At the very least you should consider whether results are right, whether your boundary conditions are correct, and if you can force error conditions.
Testing results often means making sure combinations of input get the expected results. Boundaries are reflected in the related "0, 1, many" rule, where you do silly stuff to see if your code has implicit boundaries that can be reached with bad, null or unexpected values.
For example, what happens if you pass huge Strings to your methods that take them? What about strings with weird Unicode chars in them? No line breaks?
Forcing error conditions means making sure things degrade gracefully and/or throw under the expected situation.
Think about your code as a brittle little appliance and then pretend a poo-flinging monkey, a 14-yr old hacker and your non-hacker grandmother (I know some exist) are all taking turns on it.

Related

How to close a socket which is locked in an infinite loop?

I have created a server-client project where the server keeps listening and prints the information. However, when i shutdown the client, the server remains open. The problem is that I need to insert this into another application, and, if the server does not close at first, the application will not open unless i kill the process in that port (but this is not an option to me). What should I do to properly close the server once the client disconnects?
Here is the code:
Server:
public class Server {
public static void main(String[] args) {
Connection conn = new Connection();
new Thread(conn).start();
}
private static class Connection implements Runnable {
#Override
public void run() {
try (ServerSocket serverSocket = new ServerSocket(5005)) {
Socket socket = serverSocket.accept();
listener(socket);
} catch (IOException ex) {
ex.printStackTrace();
}
}
private void listener(Socket socket) throws IOException {
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
boolean alive = true;
while (alive) {
try {
outputStream.writeUTF(new Scanner(System.in).nextLine());
System.out.println(inputStream.readUTF());
} catch (IOException ex) {
ex.printStackTrace();
alive = false;
}
}
}
}
}
Client:
public class Client {
public static void main(String[] args) {
try (Socket socket = new Socket("localhost", 5005)) {
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
while (socket.isConnected()) {
System.out.println("Incoming data: " + inputStream.readUTF());
outputStream.writeUTF(new Scanner(System.in).nextLine());
outputStream.flush();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Since now, thank you very much!
The thing that force the system wait and not close is this line at your Server.java :
outputStream.writeUTF(new Scanner(System.in).nextLine());
Once it starts waiting the user input, it waits forever along the life time of the instance although your client is disconnected.
So what you can do ? You can create another thread that makes periodic "ENTER" inputs (if you insist using new Scanner(System.in)) for example input per 5 seconds. After the enter, or any other meaningful input, if you decide this is not from your client, don't write it to the client and wait user input again (if your client still connected !). If your client is not connected, just finish your loop.
Please check Java Robot class and this example

Making Java Server to stop after certain time

I want to create a Java Server program that stops after 10 seconds.Right now, I am using setSoTimeout method. Once the time expires, I catch the exception and generate a Server Closing Message.
But that seems to be a workaround. Is there a better way to do it?
public class DailyAdviceServer
{
String[] adviceList = {"Take smaller bites", "Go for the tight jeans. No they do NOT make you look fat",
"One word: inappropriate", "Just for today, be honest. Tell your boss what you *really* think",
"You might want to rethink that haircut"};
public void startserver() {
try {
#SuppressWarnings("resource")
ServerSocket serverSock = new ServerSocket(2727);
serverSock.setSoTimeout(10000);
while (true)
{
Socket sock = serverSock.accept();
OutputStreamWriter streamwriter = new OutputStreamWriter(sock.getOutputStream());
BufferedWriter writer=new BufferedWriter(streamwriter);
String advice = getAdvice();
writer.write(advice);
writer.close();
}
} catch (SocketTimeoutException ex)
{
System.out.println("The Server has now shut down.");
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
private String getAdvice() {
int random = (int) (Math.random() * adviceList.length);
return adviceList[random];
}
public static void main(String[] args)
{
DailyAdviceServer server = new DailyAdviceServer();
server.startserver();
}
}
You can start a timer after the creation of the ServerSocket and when the timer expires you can close it

Java Socket connection only works in debug mode

I want to implement a Server which listens endless on a specific port to receive data from many clients (never in parallel, only serial). The first thing I tried is to run the server and then launch a few clients in serial (one after the other).
This sounded very easy to implement, but I actually got into the problem, that the code works only when I run it in debug mode with at least one breakpoint in the server code (but the same fault as when running it normally without a breakpoint), very strange to me.
However here is the server code:
public class TaskExecutionServer {
public TaskExecutionServer(final int port) {
new Thread() {
#Override
public void run() {
try {
int counter = 0;
ServerSocket serverSocket = new ServerSocket(port);
while(true) {
System.out.println("Waiting for client...");
Socket socket = serverSocket.accept();
System.out.println("Accepted");
InputStream inputStream = socket.getInputStream();
ObjectInputStream objectStream = new ObjectInputStream(inputStream);
while(inputStream.available() > 0 ) {
String to = (String)objectStream.readObject();
System.out.println(to);
System.out.println(++counter);
}
objectStream.close();
inputStream.close();
System.out.println("Closing socket");
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
public static void main(String args[]) {
new TaskExecutionServer(2003);
}
}
And here the client code:
public class TaskSenderClient {
public static void main(String args[]){
try{
Socket s = new Socket("localhost",2003);
OutputStream os = s.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject("test");
oos.close();
os.close();
s.close();
}catch(Exception e){
System.out.println("Client exception");
e.printStackTrace();
}
}
}
this is the console output when running in debug mode with breakpoint in the server code row System.out.println("Accepted");:
Waiting for client...
Accepted
test
1
Closing socket
Waiting for client...
Accepted
test
2
Closing socket
Waiting for client...
Accepted
test
3
Closing socket
Waiting for client...
And the output when running in normal mode / without breakpoints in debug-mode:
Waiting for client...
Accepted
test
1
Closing socket
Waiting for client...
Accepted
Closing socket
Waiting for client...
Accepted
Closing socket
Waiting for client...
I don't get any exception... Can someone help? It's my first attempt to re-use a socket connection in java.
EDIT: Checking inputStream.available returns different values
I just added a System.out.println(inputStream.available()); before the while in server code. This prints
always 7 in debug-mode with breakpoint
7 (in first run) and 0 (in all other attemps) afterwards in non-debug mode / without breakpoints
EDIT 2: First wait until inputStream.available != 0
This solution also works for me. However, I removed this code snippet here, because checking of available() seems not to be the correct way for that! -> see the solution!
EDIT 3: New server code, which uses NonEmptyInputStream which checks per PushbackInputStream for non-empty streams:
As this uses the EOFException it seems not to be an optimal solution to me, so I also removed this code snippet (instead see solution below). The usage of exceptions in "correct" code is discussed in the comments below...
InputStream.available() can return 0 if there is no data yet, meaning the client didn't send some yet or at least it is not arrived yet. If you add a breakpoint the client has more time to send the data.
You can either add logic like your client first sends how many objects it writes, the server reads the amount and then reads that many objects before it stops reading.
Another possibility would be to insert a PushbackInputStream between the ObjectInputStream and the InputStream and then do a read() on the PushbackInputStream, check the result for -1 which means end-of-stream and if it was not -1, use unread() to push the read byte back into the stream before using the ObjectInputStream methods.
Here you have an example of your originally posted class rewritten with the last pattern:
public class TaskExecutionServer {
public TaskExecutionServer(final int port) {
new Thread() {
#Override
public void run() {
try {
int counter = 0;
ServerSocket serverSocket = new ServerSocket(port);
while(true) {
System.out.println("Waiting for client...");
Socket socket = serverSocket.accept();
System.out.println("Accepted");
InputStream inputStream = socket.getInputStream();
PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
ObjectInputStream objectStream = new ObjectInputStream(pushbackInputStream);
for(int i; (i = pushbackInputStream.read()) != -1;) {
pushbackInputStream.unread(i);
String to = (String) objectStream.readObject();
System.out.println(to);
System.out.println(++counter);
}
objectStream.close();
pushbackInputStream.close();
inputStream.close();
System.out.println("Closing socket");
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
public static void main(String args[]) {
new TaskExecutionServer(2003);
}
}
or here again with try-with-resources which is preferable over manually closing AutoClosables.
public class TaskExecutionServer {
public TaskExecutionServer(final int port) {
new Thread() {
#Override
public void run() {
try (ServerSocket serverSocket = new ServerSocket(port)) {
int counter = 0;
while(true) {
System.out.println("Waiting for client...");
try (Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
ObjectInputStream objectStream = new ObjectInputStream(pushbackInputStream)) {
System.out.println("Accepted");
for(int i; (i = pushbackInputStream.read()) != -1;) {
pushbackInputStream.unread(i);
String to = (String) objectStream.readObject();
System.out.println(to);
System.out.println(++counter);
}
System.out.println("Closing socket");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
public static void main(String args[]) {
new TaskExecutionServer(2003);
}
}
available() is not a valid test for end of stream. See the Javadoc. You should read from the object stream until EOFException is caught.

Java Sockets - Running the same client multiple times in parallel.

(Disclaimer that some of this code will be similar to online tutorials)
I think I've made it so that my server can handle multiple requests at once using threads, but I'm not entirely sure. And on top of that I don't know how I would actually send multiple requests at once.
My goal is to run my client code multiple times in parallel to see what happens if multiple clients connect to the server at the same time.
Client code (in separate project package):
Client clientSocket = new Client(9990,"localhost");
Socket socket = new Socket(clientSocket.host,clientSocket.portNumber);
clientSocket.performTask(socket);
("performTask(socket)" sends data to the server to perform a task)
Server code (separate project package from client code):
Server server = new Server(9990);
int clientNumber = 0;
ServerSocket socket = new ServerSocket(server.portNumber);
try {
while (true) {
new ServerHandler(socket.accept(),clientNumber).go();
clientNumber++;
}
}
finally {
socket.close();
}
}
ServerHandler class (same project package as server code):
public class ServerHandler extends Thread {
private static Socket socket;
private static int clientNumber;
public ServerHandler(Socket socket, int clientNumber) {
ServerHandler.socket = socket;
ServerHandler.clientNumber = clientNumber;
}
public void go() {
while(true) {
try {
//do calculation, do server tasks, etc.
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
So when the client connects to the server, the server implements the ServerHandler class to do the necessary calculations: the idea in doing that was so that multiple clients could connect all at the same time.
So my question is then in two parts:
(1) Have I set up my programs to allow for multi-threading, or have I made a mistake somewhere along the way? (e.g. someone told me I needed to use "Runnable" somewhere to use multi-threading, and I notice I haven't)
(2) After fixing my code to allow for multi-threading, how would I actually use it to let me run my client code in parallel?
Ok for starters, your ServerHandler extends the Thread class. Therefore to make it run as a seperate thread, always invoke by calling the start() method. You are calling you custom go method which will make the ServerHandler execute in the same thread as your infinite while loop. So it should be something like this ServerHandler(socket.accept(),clientNumber).start(). Also it is always better to implement Runnable because java does not support multiple inheritance via the "extends" concept. Therefore in the future if your ServerHandler needs to actually extend a custom class, it wont be able to since it already extends the Thread class. Its better to implement interfaces since there is no limit as to how many you can implement.
Hence implementing the Runnable interface is a good design choice. You can run your client code in parallel by making the client into a threaded model. Here is one such example of multiple client sockets connecting to the server in parallel
Server Code
public class WebServer {
static int hitCount = 0;
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(7777, 10000);
while (true) {
Socket defaultSocket = serverSocket.accept();
new Thread(new ServerSlave(defaultSocket)).start();
System.out.println("Size is :" + hitCount);
}
}
}
class ServerSlave implements Runnable {
Socket clientSocket;
public ServerSlave(Socket socket) {
clientSocket = socket;
WebServer.hitCount++;
}
public void run() {
try {
DataInputStream inputStream = new DataInputStream(clientSocket.getInputStream());
DataOutputStream outputStream = new DataOutputStream(clientSocket.getOutputStream());
System.out.println(inputStream.readUTF());
outputStream.writeUTF("Thank you for contacting the web server");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Client Code :
public class Client {
static int excepCount=0;
public static void main(String[] args) throws Exception {
for (int i = 0; i < 100; i++) {
new Thread(new Worker("" + i)).start();
}
Thread.sleep(10000);
System.out.println( Client.excepCount);
}
}
class Worker implements Runnable {
String clientName;
public Worker(String name) {
clientName = name;
}
public void run() {
System.out.println("Process started for : " + clientName);
Socket socket = null;
try {
socket = new Socket("127.0.0.1", 7777);
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
outputStream.writeUTF("Hello socket. Client number " + clientName + "here");
InputStream inFromServer = socket.getInputStream();
DataInputStream in =
new DataInputStream(inFromServer);
System.out.println("Server says " + in.readUTF());
System.out.println("Closing socket");
} catch (IOException e) {
Client.excepCount++;
e.printStackTrace();
}finally{
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
You should use multithreading .
You have to rename method to "run"/ and call that method using "start".Please change Server side code to
try {
while (true) {
new ServerHandler(socket.accept(),clientNumber).start();
clientNumber++;
}
}
finally {
socket.close();
}
and client side
public class ServerHandler extends Thread {
private static Socket socket;
private static int clientNumber;
public ServerHandler(Socket socket, int clientNumber) {
ServerHandler.socket = socket;
ServerHandler.clientNumber = clientNumber;
}
public void run() {
while(true) {
try {
//do calculation, do server tasks, etc.
}
} catch (IOException e) {
e.printStackTrace();
}
}

MultiThreaded Server, which is a client to another server

I'm using a server socket to accept clients on the main thread, when a thread is accepted,the clients socket is given to a handler which is started in a new thread to process communications. However, before I start running my server to access clients, it connects to a second server which it must list to and be able to respond to and pass on the messages it gets to it's clients.
Hopefully this image illustrate what I mean:
The small server must be continuously listening for input from the big server, and also able to output responses.
//Default constructor
private smallServer(){}
//method to initialise and start the server
public static void StartServer(int port) throws IOException {
smallServer ss = new smallServer();
ss.bs= new bigServerClient(ss);
Thread nsc_Thread = new Thread(ss.bsc);
bsc_Thread.start();
//accepts clients and starts new thread for them
ss.ServerRun(port);
}
private void ServerRun(int port) throws IOException {
ServerSocket server = new ServerSocket(port);
server.setSoTimeout(50);
while (run) {
Socket client = null;
try {
client = server.accept();
} catch (SocketTimeoutException e) {
}
if (client != null) {
ClientHandler handler = new ClientHandler(client, this);
Thread handleThread = new Thread(handler);
handleThread.start();
}
}
if (!run) {
synchronized (ClientHandler.handlers) {
for (ClientHandler handler : ClientHandler.handlers) {
handler.terminateHandler();
}
}
System.exit(0);
}
}
public void processBigServerCommand(String toProcess) {
System.out.println("RESEAVED: " + toProcess);
}
The big server client(on the small server) then does this:
public class bigServerClient implements Runnable {
private smalsServer ss;
private PrintWriter printer;
private BufferedReader reader;
private Socket socket;
public bigServerClient(smallServer _ss) throws IOException {
ss = _ss;
socket = new Socket("Localhost", 5000);
printer = new PrintWriter(socket.getOutputStream());
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
printer.flush();
SendBigServerMessage("Starting String");
}
private void SendBigServerMessage(String toSend) {
printer.print(toSend);
printer.flush();
}
#Override
public void run() {
try {
while (ss.state()) {
String inputLine;
while ((inputLine = reader.readLine()) != null) {
ss.processBigServerCommand(inputLine);
System.out.println(inputLine);
}
}
} catch (IOException e) {
} finally {
try {
socket.close();
} catch (IOException ex) {
}
}
}
}
From what's above, can anyone see why the big server client isn't responding to the big server when a message is sent? I'm guessing it's something to do with the main thread blocking the second thread, but I'm not sure... Any help would be greatly appreciated.
You lost me in your code...
Simplify it.
Your smallServer (see class names conventions) should have persistent connection to BigServer (effectively it is BigServer client) - you can implement it in your smallServer class, it should connect (once) and open I/O to BigServer (once) and close everything once the connection is terminated.
As your smallServer will handle multiple clients and pass their requests to BigServer there is no guarantee of the order of BigServer responses - you should do something to handle that (maybe pass UUID with requests?)
Simplify your smallServer and make sure that it runs...

Categories