8157917: JShell: shutdown could cause remote JDWP errors to be visible to users
8157918: JShell tests: StartOptionTest displays insufficient information to diagnose failures Reviewed-by: vromero
This commit is contained in:
parent
f9526a87fe
commit
1fb5067c57
@ -50,6 +50,7 @@ import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
|
|||||||
class JDIConnection {
|
class JDIConnection {
|
||||||
|
|
||||||
private VirtualMachine vm;
|
private VirtualMachine vm;
|
||||||
|
private boolean active = true;
|
||||||
private Process process = null;
|
private Process process = null;
|
||||||
private int outputCompleteCount = 0;
|
private int outputCompleteCount = 0;
|
||||||
|
|
||||||
@ -175,6 +176,11 @@ class JDIConnection {
|
|||||||
return process != null && process.isAlive();
|
return process != null && process.isAlive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Beginning shutdown, ignore any random dying squeals
|
||||||
|
void beginShutdown() {
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void disposeVM() {
|
public synchronized void disposeVM() {
|
||||||
try {
|
try {
|
||||||
if (vm != null) {
|
if (vm != null) {
|
||||||
@ -233,14 +239,19 @@ class JDIConnection {
|
|||||||
int i;
|
int i;
|
||||||
try {
|
try {
|
||||||
while ((i = in.read()) != -1) {
|
while ((i = in.read()) != -1) {
|
||||||
pStream.print((char) i);
|
// directly copy input to output, but skip if asked to close
|
||||||
|
if (active) {
|
||||||
|
pStream.print((char) i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
String s = ex.getMessage();
|
String s = ex.getMessage();
|
||||||
if (!s.startsWith("Bad file number")) {
|
if (active && !s.startsWith("Bad file number")) {
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
// else we got a Bad file number IOException which just means
|
// else we are being shutdown (and don't want any spurious death
|
||||||
|
// throws to ripple) or
|
||||||
|
// we got a Bad file number IOException which just means
|
||||||
// that the debuggee has gone away. We'll just treat it the
|
// that the debuggee has gone away. We'll just treat it the
|
||||||
// same as if we got an EOF.
|
// same as if we got an EOF.
|
||||||
}
|
}
|
||||||
|
@ -109,11 +109,14 @@ public class JDIExecutionControl implements ExecutionControl {
|
|||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
try {
|
try {
|
||||||
|
JDIConnection c = jdiEnv.connection();
|
||||||
|
if (c != null) {
|
||||||
|
c.beginShutdown();
|
||||||
|
}
|
||||||
if (remoteOut != null) {
|
if (remoteOut != null) {
|
||||||
remoteOut.writeInt(CMD_EXIT);
|
remoteOut.writeInt(CMD_EXIT);
|
||||||
remoteOut.flush();
|
remoteOut.flush();
|
||||||
}
|
}
|
||||||
JDIConnection c = jdiEnv.connection();
|
|
||||||
if (c != null) {
|
if (c != null) {
|
||||||
c.disposeVM();
|
c.disposeVM();
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@ -48,85 +47,76 @@ import org.testng.annotations.Test;
|
|||||||
|
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
import static org.testng.Assert.assertTrue;
|
import static org.testng.Assert.assertTrue;
|
||||||
import static org.testng.Assert.fail;
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public class StartOptionTest {
|
public class StartOptionTest {
|
||||||
|
|
||||||
private ByteArrayOutputStream out;
|
private ByteArrayOutputStream cmdout;
|
||||||
private ByteArrayOutputStream err;
|
private ByteArrayOutputStream cmderr;
|
||||||
|
private ByteArrayOutputStream console;
|
||||||
|
private ByteArrayOutputStream userout;
|
||||||
|
private ByteArrayOutputStream usererr;
|
||||||
|
|
||||||
private JShellTool getShellTool() {
|
private JShellTool getShellTool() {
|
||||||
class NoOutputAllowedStream extends OutputStream {
|
|
||||||
private final String label;
|
|
||||||
NoOutputAllowedStream(String label) {
|
|
||||||
this.label = label;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void write(int b) { fail("Unexpected output to: " + label); }
|
|
||||||
}
|
|
||||||
return new JShellTool(
|
return new JShellTool(
|
||||||
new TestingInputStream(),
|
new TestingInputStream(),
|
||||||
new PrintStream(out),
|
new PrintStream(cmdout),
|
||||||
new PrintStream(err),
|
new PrintStream(cmderr),
|
||||||
new PrintStream(new NoOutputAllowedStream("console")),
|
new PrintStream(console),
|
||||||
new TestingInputStream(),
|
new TestingInputStream(),
|
||||||
new PrintStream(new NoOutputAllowedStream("userout")),
|
new PrintStream(userout),
|
||||||
new PrintStream(new NoOutputAllowedStream("usererr")),
|
new PrintStream(usererr),
|
||||||
new ReplToolTesting.MemoryPreferences(),
|
new ReplToolTesting.MemoryPreferences(),
|
||||||
Locale.ROOT);
|
Locale.ROOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getOutput() {
|
private void check(ByteArrayOutputStream str, Consumer<String> checkOut, String label) {
|
||||||
byte[] bytes = out.toByteArray();
|
byte[] bytes = str.toByteArray();
|
||||||
out.reset();
|
str.reset();
|
||||||
return new String(bytes, StandardCharsets.UTF_8);
|
String out = new String(bytes, StandardCharsets.UTF_8);
|
||||||
}
|
if (checkOut != null) {
|
||||||
|
checkOut.accept(out);
|
||||||
private String getError() {
|
} else {
|
||||||
byte[] bytes = err.toByteArray();
|
assertEquals("", out, label + ": Expected empty -- ");
|
||||||
err.reset();
|
}
|
||||||
return new String(bytes, StandardCharsets.UTF_8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void start(Consumer<String> checkOutput, Consumer<String> checkError, String... args) throws Exception {
|
private void start(Consumer<String> checkOutput, Consumer<String> checkError, String... args) throws Exception {
|
||||||
JShellTool tool = getShellTool();
|
JShellTool tool = getShellTool();
|
||||||
tool.start(args);
|
tool.start(args);
|
||||||
if (checkOutput != null) {
|
check(cmdout, checkOutput, "cmdout");
|
||||||
checkOutput.accept(getOutput());
|
check(cmderr, checkError, "cmderr");
|
||||||
} else {
|
check(console, null, "console");
|
||||||
assertEquals("", getOutput(), "Output: ");
|
check(userout, null, "userout");
|
||||||
}
|
check(usererr, null, "usererr");
|
||||||
if (checkError != null) {
|
|
||||||
checkError.accept(getError());
|
|
||||||
} else {
|
|
||||||
assertEquals("", getError(), "Error: ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void start(String expectedOutput, String expectedError, String... args) throws Exception {
|
private void start(String expectedOutput, String expectedError, String... args) throws Exception {
|
||||||
start(s -> assertEquals(s.trim(), expectedOutput, "Output: "), s -> assertEquals(s.trim(), expectedError, "Error: "), args);
|
start(s -> assertEquals(s.trim(), expectedOutput, "cmdout: "), s -> assertEquals(s.trim(), expectedError, "cmderr: "), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeMethod
|
@BeforeMethod
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
out = new ByteArrayOutputStream();
|
cmdout = new ByteArrayOutputStream();
|
||||||
err = new ByteArrayOutputStream();
|
cmderr = new ByteArrayOutputStream();
|
||||||
|
console = new ByteArrayOutputStream();
|
||||||
|
userout = new ByteArrayOutputStream();
|
||||||
|
usererr = new ByteArrayOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUsage() throws Exception {
|
public void testUsage() throws Exception {
|
||||||
start(s -> {
|
start(s -> {
|
||||||
assertTrue(s.split("\n").length >= 7, s);
|
assertTrue(s.split("\n").length >= 7, "Not enough usage lines: " + s);
|
||||||
assertTrue(s.startsWith("Usage: jshell <options>"), s);
|
assertTrue(s.startsWith("Usage: jshell <options>"), "Unexpect usage start: " + s);
|
||||||
}, null, "-help");
|
}, null, "-help");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUnknown() throws Exception {
|
public void testUnknown() throws Exception {
|
||||||
start(s -> {
|
start(s -> {
|
||||||
assertTrue(s.split("\n").length >= 7, s);
|
assertTrue(s.split("\n").length >= 7, "Not enough usage lines (unknown): " + s);
|
||||||
assertTrue(s.startsWith("Usage: jshell <options>"), s);
|
assertTrue(s.startsWith("Usage: jshell <options>"), "Unexpect usage start (unknown): " + s);
|
||||||
}, s -> assertEquals(s.trim(), "Unknown option: -unknown"), "-unknown");
|
}, s -> assertEquals(s.trim(), "Unknown option: -unknown"), "-unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,12 +147,15 @@ public class StartOptionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testVersion() throws Exception {
|
public void testVersion() throws Exception {
|
||||||
start(s -> assertTrue(s.startsWith("jshell")), null, "-version");
|
start(s -> assertTrue(s.startsWith("jshell"), "unexpected version: " + s), null, "-version");
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterMethod
|
@AfterMethod
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
out = null;
|
cmdout = null;
|
||||||
err = null;
|
cmderr = null;
|
||||||
|
console = null;
|
||||||
|
userout = null;
|
||||||
|
usererr = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user