3bc69d393d
Co-authored-by: Alan Bateman <alan.bateman@oracle.com> Co-authored-by: Alex Buckley <alex.buckley@oracle.com> Co-authored-by: Erik Joelsson <erik.joelsson@oracle.com> Co-authored-by: Jonathan Gibbons <jonathan.gibbons@oracle.com> Co-authored-by: Karen Kinnear <karen.kinnear@oracle.com> Co-authored-by: Magnus Ihse Bursie <magnus.ihse.bursie@oracle.com> Co-authored-by: Mandy Chung <mandy.chung@oracle.com> Co-authored-by: Mark Reinhold <mark.reinhold@oracle.com> Co-authored-by: Paul Sandoz <paul.sandoz@oracle.com> Reviewed-by: alanb, chegar, ihse, mduigou
400 lines
14 KiB
Java
400 lines
14 KiB
Java
/*
|
|
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
|
|
/* @test
|
|
* @summary Test chat server chatserver test
|
|
*
|
|
* @library ../../../src/sample/share/nio/chatserver
|
|
* @build ChatTest ChatServer Client ClientReader DataReader MessageReader NameReader
|
|
* @run main ChatTest
|
|
*/
|
|
|
|
import java.io.*;
|
|
import java.net.InetSocketAddress;
|
|
import java.net.Socket;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.concurrent.CyclicBarrier;
|
|
|
|
public class ChatTest {
|
|
public static int listeningPort = 0;
|
|
|
|
public static void main(String[] args) throws Throwable {
|
|
testStartStop();
|
|
testPortOpen();
|
|
testAsksForName();
|
|
testUseName();
|
|
testConnectDisconnectConnect();
|
|
testUsernameAndMessage();
|
|
testDontReceiveMessageInNameState();
|
|
}
|
|
|
|
private static ChatServer startServer() throws IOException {
|
|
ChatServer server = new ChatServer(0);
|
|
InetSocketAddress address = (InetSocketAddress) server.getSocketAddress();
|
|
listeningPort = address.getPort();
|
|
server.run();
|
|
return server;
|
|
}
|
|
|
|
public static void testStartStop() throws Exception {
|
|
ChatServer server = startServer();
|
|
server.shutdown();
|
|
}
|
|
|
|
public static void testPortOpen() throws Exception {
|
|
ChatServer server = startServer();
|
|
try {
|
|
Socket socket = new Socket("localhost", listeningPort);
|
|
if (!socket.isConnected()) {
|
|
throw new RuntimeException("Failed to connect to server: port not open");
|
|
}
|
|
} finally {
|
|
server.shutdown();
|
|
}
|
|
}
|
|
|
|
public static void testAsksForName() throws Exception {
|
|
ChatServer server = startServer();
|
|
try {
|
|
Socket socket = new Socket("localhost", listeningPort);
|
|
|
|
Reader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
|
String string = readAvailableString(reader);
|
|
if (!string.equals("Name: ")) {
|
|
throw new RuntimeException("Server doesn't send Name: ");
|
|
}
|
|
} finally {
|
|
server.shutdown();
|
|
}
|
|
}
|
|
|
|
public static void testUseName() throws Throwable {
|
|
ChatServer server = startServer();
|
|
try {
|
|
performTestUseName();
|
|
} finally {
|
|
server.shutdown();
|
|
}
|
|
}
|
|
|
|
public static void testConnectDisconnectConnect() throws Exception {
|
|
ChatServer server = startServer();
|
|
try {
|
|
performTestConnectDisconnectConnect();
|
|
} finally {
|
|
server.shutdown();
|
|
}
|
|
}
|
|
|
|
public static void testUsernameAndMessage() throws Exception {
|
|
ChatServer server = startServer();
|
|
try {
|
|
performTestUsernameAndMessage();
|
|
} finally {
|
|
server.shutdown();
|
|
}
|
|
}
|
|
|
|
public static void testDontReceiveMessageInNameState() throws Exception {
|
|
ChatServer server = startServer();
|
|
try {
|
|
performDontReceiveMessageInNameState();
|
|
} finally {
|
|
server.shutdown();
|
|
}
|
|
}
|
|
|
|
private static void assertEqual(List<Exception> exception, Object value, Object expected) {
|
|
if (expected == value) {
|
|
return;
|
|
}
|
|
if (expected == null) {
|
|
exception.add(new RuntimeException("Expected null, but was: " + value));
|
|
return;
|
|
}
|
|
if (!expected.equals(value)) {
|
|
exception.add(new RuntimeException("Expected: " + expected + " but was: " + value));
|
|
return;
|
|
}
|
|
}
|
|
|
|
private static void performDontReceiveMessageInNameState() throws Exception {
|
|
final CyclicBarrier barrier1 = new CyclicBarrier(2);
|
|
final CyclicBarrier barrier2 = new CyclicBarrier(2);
|
|
final CyclicBarrier barrier3 = new CyclicBarrier(2);
|
|
final List<Exception> exceptions = Collections.synchronizedList(new ArrayList<Exception>());
|
|
|
|
ChatConnection chatConnection = new ChatConnection() {
|
|
@Override
|
|
public void run(Socket socket, BufferedReader reader, Writer writer) throws Exception {
|
|
String string = readAvailableString(reader);
|
|
assertEqual(exceptions, string, "Name: ");
|
|
writer.write("testClient1\n");
|
|
waitForJoin(reader, "testClient1");
|
|
barrier1.await();
|
|
writer.write("Ignore this!\n");
|
|
barrier2.await();
|
|
barrier3.await();
|
|
}
|
|
};
|
|
|
|
Thread client2 = new Thread(new ChatConnection() {
|
|
@Override
|
|
public void run(Socket socket, BufferedReader reader, Writer writer) throws Exception {
|
|
barrier1.await();
|
|
barrier2.await();
|
|
String string = readAvailableString(reader);
|
|
assertEqual(exceptions, string, "Name: ");
|
|
string = readAvailableString(reader, true);
|
|
assertEqual(exceptions, string, null);
|
|
writer.write("testClient2\n");
|
|
barrier3.await();
|
|
}
|
|
});
|
|
|
|
client2.start();
|
|
chatConnection.run();
|
|
if (!exceptions.isEmpty()) {
|
|
throw exceptions.get(0);
|
|
}
|
|
|
|
}
|
|
|
|
private static void waitForJoin(BufferedReader reader, String s) throws IOException {
|
|
String joined;
|
|
do {
|
|
joined = readAvailableString(reader);
|
|
} while (!(joined != null && joined.contains("Welcome " + s)));
|
|
}
|
|
|
|
private static void performTestUsernameAndMessage() throws Exception {
|
|
final CyclicBarrier barrier1 = new CyclicBarrier(2);
|
|
final CyclicBarrier barrier2 = new CyclicBarrier(2);
|
|
final CyclicBarrier barrier3 = new CyclicBarrier(2);
|
|
final List<Exception> exceptions = Collections.synchronizedList(new ArrayList<Exception>());
|
|
|
|
ChatConnection chatConnection = new ChatConnection() {
|
|
@Override
|
|
public void run(Socket socket, BufferedReader reader, Writer writer) throws Exception {
|
|
String string = readAvailableString(reader);
|
|
assertEqual(exceptions, string, "Name: ");
|
|
writer.write("testClient1\n");
|
|
waitForJoin(reader, "testClient1");
|
|
barrier1.await();
|
|
barrier2.await();
|
|
string = readAvailableString(reader);
|
|
assertEqual(exceptions, string, "testClient2: Hello world!\n");
|
|
barrier3.await();
|
|
}
|
|
};
|
|
|
|
Thread client2 = new Thread(new ChatConnection() {
|
|
@Override
|
|
public void run(Socket socket, BufferedReader reader, Writer writer) throws Exception {
|
|
String string = readAvailableString(reader);
|
|
assertEqual(exceptions, string, "Name: ");
|
|
barrier1.await();
|
|
writer.write("testClient2\nHello world!\n");
|
|
barrier2.await();
|
|
barrier3.await();
|
|
}
|
|
});
|
|
|
|
client2.start();
|
|
chatConnection.run();
|
|
if (!exceptions.isEmpty()) {
|
|
throw exceptions.get(0);
|
|
}
|
|
}
|
|
|
|
private static void performTestConnectDisconnectConnect() throws Exception {
|
|
final CyclicBarrier barrier1 = new CyclicBarrier(2);
|
|
final CyclicBarrier barrier2 = new CyclicBarrier(2);
|
|
final CyclicBarrier barrier3 = new CyclicBarrier(2);
|
|
final List<Exception> exceptions = new ArrayList<Exception>();
|
|
|
|
ChatConnection chatConnection = new ChatConnection() {
|
|
@Override
|
|
public void run(Socket socket, BufferedReader reader, Writer writer) throws Exception {
|
|
String string = readAvailableString(reader);
|
|
assertEqual(exceptions, string, "Name: ");
|
|
writer.write("testClient1\n");
|
|
}
|
|
};
|
|
|
|
ChatConnection chatConnection2 = new ChatConnection() {
|
|
@Override
|
|
public void run(Socket socket, BufferedReader reader, Writer writer) throws Exception {
|
|
readAvailableString(reader);
|
|
writer.write("testClient1\n");
|
|
waitForJoin(reader, "testClient1");
|
|
barrier1.await();
|
|
writer.write("Good morning!\n");
|
|
barrier2.await();
|
|
String string = readAvailableString(reader);
|
|
assertEqual(exceptions, string, "testClient2: Hello world!\n");
|
|
barrier3.await();
|
|
}
|
|
};
|
|
|
|
Thread client2 = new Thread(new ChatConnection() {
|
|
@Override
|
|
public void run(Socket socket, BufferedReader reader, Writer writer) throws Exception {
|
|
readAvailableString(reader);
|
|
writer.write("testClient2\n");
|
|
waitForJoin(reader, "testClient2");
|
|
barrier1.await();
|
|
writer.write("Hello world!\n");
|
|
barrier2.await();
|
|
String string = readAvailableString(reader);
|
|
assertEqual(exceptions, string, "testClient1: Good morning!\n");
|
|
barrier3.await();
|
|
}
|
|
});
|
|
|
|
client2.start();
|
|
chatConnection.run();
|
|
chatConnection2.run();
|
|
if (!exceptions.isEmpty()) {
|
|
throw exceptions.get(0);
|
|
}
|
|
}
|
|
|
|
private static void performTestUseName() throws Exception {
|
|
final CyclicBarrier barrier1 = new CyclicBarrier(2);
|
|
final CyclicBarrier barrier2 = new CyclicBarrier(2);
|
|
final CyclicBarrier barrier3 = new CyclicBarrier(2);
|
|
final List<Exception> exceptions = new ArrayList<Exception>();
|
|
|
|
ChatConnection chatConnection = new ChatConnection() {
|
|
@Override
|
|
public void run(Socket socket, BufferedReader reader, Writer writer) throws Exception {
|
|
String string = readAvailableString(reader);
|
|
if (!"Name: ".equals(string)) {
|
|
exceptions.add(new RuntimeException("Expected Name: "));
|
|
}
|
|
writer.write("testClient1\n");
|
|
waitForJoin(reader, "testClient1");
|
|
barrier1.await();
|
|
barrier2.await();
|
|
string = readAvailableString(reader);
|
|
if (!"testClient2: Hello world!\n".equals(string)) {
|
|
exceptions.add(new RuntimeException("testClient2: Hello world!\n"));
|
|
}
|
|
barrier3.await();
|
|
}
|
|
};
|
|
|
|
Thread client2 = new Thread(new ChatConnection() {
|
|
@Override
|
|
public void run(Socket socket, BufferedReader reader, Writer writer) throws Exception {
|
|
String string = readAvailableString(reader);
|
|
if (!"Name: ".equals(string)) {
|
|
exceptions.add(new RuntimeException("Expected Name: "));
|
|
}
|
|
writer.write("testClient2\n");
|
|
waitForJoin(reader, "testClient2");
|
|
barrier1.await();
|
|
writer.write("Hello world!\n");
|
|
barrier2.await();
|
|
barrier3.await();
|
|
}
|
|
});
|
|
|
|
client2.start();
|
|
chatConnection.run();
|
|
if (!exceptions.isEmpty()) {
|
|
throw exceptions.get(0);
|
|
}
|
|
}
|
|
|
|
private static String readAvailableString(Reader reader) throws IOException {
|
|
return readAvailableString(reader, false);
|
|
}
|
|
|
|
private static String readAvailableString(Reader reader, boolean now) throws IOException {
|
|
StringBuilder builder = new StringBuilder();
|
|
int bytes;
|
|
if (now && !reader.ready()) {
|
|
return null;
|
|
}
|
|
do {
|
|
char[] buf = new char[256];
|
|
bytes = reader.read(buf);
|
|
builder.append(buf, 0, bytes);
|
|
} while (bytes == 256);
|
|
return builder.toString();
|
|
}
|
|
|
|
private abstract static class ChatConnection implements Runnable {
|
|
public Exception exception;
|
|
|
|
@Override
|
|
public void run() {
|
|
try (Socket socket = new Socket("localhost", listeningPort);
|
|
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
|
Writer writer = new FlushingWriter(new OutputStreamWriter(socket.getOutputStream()))) {
|
|
socket.setTcpNoDelay(true);
|
|
|
|
run(socket, reader, writer);
|
|
} catch (Exception e) {
|
|
exception = e;
|
|
}
|
|
}
|
|
|
|
public abstract void run(Socket socket, BufferedReader reader, Writer writer) throws Exception;
|
|
}
|
|
|
|
private static class FlushingWriter extends Writer {
|
|
public final Writer delegate;
|
|
|
|
private FlushingWriter(Writer delegate) {
|
|
this.delegate = delegate;
|
|
}
|
|
|
|
@Override
|
|
public void write(char[] cbuf, int off, int len) throws IOException {
|
|
delegate.write(cbuf, off, len);
|
|
}
|
|
|
|
@Override
|
|
public void flush() throws IOException {
|
|
delegate.flush();
|
|
}
|
|
|
|
@Override
|
|
public void close() throws IOException {
|
|
delegate.close();
|
|
}
|
|
|
|
@Override
|
|
public void write(String str) throws IOException {
|
|
super.write(str);
|
|
flush();
|
|
}
|
|
}
|
|
}
|