pitclipse
pitclipse copied to clipboard
Test failures with Java 17
These two tests always fail when the underlying JVM is Java 17:
org.pitest.pitclipse.runner.io.ObjectStreamSocketTest.writeThrowsException()
org.pitest.pitclipse.runner.io.ObjectStreamSocketTest.readThrowsException()
They mock the socket like that:
@Test
public void readThrowsException() throws IOException, ClassNotFoundException {
InputStream inputStream = spy(new ByteArrayInputStream(asBytes(expectedObject)));
OutputStream outputStream = new ByteArrayOutputStream();
when(underlyingSocket.getInputStream()).thenReturn(inputStream);
when(underlyingSocket.getOutputStream()).thenReturn(outputStream);
objectSocket = ObjectStreamSocket.make(underlyingSocket);
objectSocket.read(); // succeeds
try {
objectSocket.read(); // EOF
fail("should not get here");
} catch (Exception e) {
assertTrue(e.getClass().getCanonicalName(),
e instanceof RuntimeException);
}
}
The failure is when we call objectSocket = ObjectStreamSocket.make(underlyingSocket);
This is the interesting exception trace
Caused by: java.io.EOFException
at java.base/java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2915)
at java.base/java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:3410)
at java.base/java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:954)
at java.base/java.io.ObjectInputStream.<init>(ObjectInputStream.java:392)
at org.pitest.pitclipse.runner.io.ObjectStreamSocket.make(ObjectStreamSocket.java:51)
... 46 more
That is
public static ObjectStreamSocket make(Socket underlyingSocket) {
try {
ObjectOutputStream outputStream = new ObjectOutputStream(underlyingSocket.getOutputStream());
ObjectInputStream inputStream = new ObjectInputStream(underlyingSocket.getInputStream());
return make(underlyingSocket, inputStream, outputStream);
} catch (IOException e) {
throw new StreamInitialisationException(e);
}
}
Maybe that is due to some changes in the implementation in Java 17: the constructor reads the header (maybe that was not the case in Java 11?), and this generates an EOF since we indeed have an empty socket:
/**
* Creates an ObjectInputStream that reads from the specified InputStream.
* A serialization stream header is read from the stream and verified.
* This constructor will block until the corresponding ObjectOutputStream
* has written and flushed the header.
*
* <p>The constructor initializes the deserialization filter to the filter returned
* by invoking the {@link Config#getSerialFilterFactory()} with {@code null} for the current filter
* and the {@linkplain Config#getSerialFilter() static JVM-wide filter} for the requested filter.
*
* <p>If a security manager is installed, this constructor will check for
* the "enableSubclassImplementation" SerializablePermission when invoked
* directly or indirectly by the constructor of a subclass which overrides
* the ObjectInputStream.readFields or ObjectInputStream.readUnshared
* methods.
*
* @param in input stream to read from
* @throws StreamCorruptedException if the stream header is incorrect
* @throws IOException if an I/O error occurs while reading stream header
* @throws SecurityException if untrusted subclass illegally overrides
* security-sensitive methods
* @throws NullPointerException if {@code in} is {@code null}
* @see ObjectInputStream#ObjectInputStream()
* @see ObjectInputStream#readFields()
* @see ObjectOutputStream#ObjectOutputStream(OutputStream)
*/
public ObjectInputStream(InputStream in) throws IOException {
verifySubclass();
bin = new BlockDataInputStream(in);
handles = new HandleTable(10);
vlist = new ValidationList();
streamFilterSet = false;
serialFilter = Config.getSerialFilterFactorySingleton().apply(null, Config.getSerialFilter());
enableOverride = false;
readStreamHeader();
bin.setBlockDataMode(true);
}
In Java 8 we have
public ObjectInputStream(InputStream in) throws IOException {
verifySubclass();
bin = new BlockDataInputStream(in);
handles = new HandleTable(10);
vlist = new ValidationList();
serialFilter = ObjectInputFilter.Config.getSerialFilter();
enableOverride = false;
readStreamHeader();
bin.setBlockDataMode(true);
}
protected void readStreamHeader()
throws IOException, StreamCorruptedException
{
short s0 = bin.readShort();
short s1 = bin.readShort();
if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) {
throw new StreamCorruptedException(
String.format("invalid stream header: %04X%04X", s0, s1));
}
}
public short readShort() throws IOException {
if (!blkmode) {
pos = 0;
in.readFully(buf, 0, 2);
} else if (end - pos < 2) {
return din.readShort();
}
short v = Bits.getShort(buf, pos);
pos += 2;
return v;
}
So readFully
was not used and we didn't get any exception. Probably it's like that also in Java 11.