I have a set of JUnit tests for my ClientHandler class. Each test works fine when run alone, but when run together, they randomly throw a java.io.IOException: Read end dead.
I have already tried to:
- Synchronized each method to prevent concurrency issues.
- Added a latch to the ClientHandler’s run() method.
- Tested the ClientHandler in a real-world simulation where it works fine.
Below is an example of one of these tests; the others are very similar, differing only in which method they verify.
<code>@Test
public synchronized void placeMsgTest() throws Exception {
ClientHandlerTestSetup setup = setupClientHandler();
ObjectOutputStream toClientHandler = setup.toClientHandler();
ControllerInterface mockController = setup.controller();
LightPlacement fakePlacement = new LightPlacement(new Position(0, 0), new LightCard(0), CardFace.FRONT);
ClientMsg placeMsg = new PlaceMsg(fakePlacement);
toClientHandler.writeObject(placeMsg);
toClientHandler.flush();
Thread.sleep(10);
verify(mockController, times(1)).place(fakePlacement);
}
private synchronized ClientHandlerTestSetup setupClientHandler() throws IOException {
PipedInputStream inputPipe = new PipedInputStream();
PipedOutputStream outputPipe = new PipedOutputStream();
inputPipe.connect(outputPipe);
ByteArrayOutputStream fromClientHandler = new ByteArrayOutputStream();
Socket mockClient = mock(Socket.class);
when(mockClient.getOutputStream()).thenReturn(fromClientHandler);
when(mockClient.getInputStream()).thenReturn(inputPipe);
when(mockClient.getInetAddress()).thenReturn(null);
VirtualView mockView = mock(VirtualView.class);
ControllerInterface mockController = mock(ControllerInterface.class);
ClientHandler clientHandler = new ClientHandler(mockClient);
Thread clientHandlerThread = new Thread(clientHandler, "testedClientHandler");
clientHandlerThread.start();
clientHandler.setOwner(mockView);
clientHandler.setController(mockController);
ObjectOutputStream toClientHandler = new ObjectOutputStream(outputPipe);
return new ClientHandlerTestSetup(clientHandler, toClientHandler, mockController);
}
private record ClientHandlerTestSetup(ClientHandler clientHandler, ObjectOutputStream toClientHandler, ControllerInterface controller) {}
</code>
<code>@Test
public synchronized void placeMsgTest() throws Exception {
ClientHandlerTestSetup setup = setupClientHandler();
ObjectOutputStream toClientHandler = setup.toClientHandler();
ControllerInterface mockController = setup.controller();
LightPlacement fakePlacement = new LightPlacement(new Position(0, 0), new LightCard(0), CardFace.FRONT);
ClientMsg placeMsg = new PlaceMsg(fakePlacement);
toClientHandler.writeObject(placeMsg);
toClientHandler.flush();
Thread.sleep(10);
verify(mockController, times(1)).place(fakePlacement);
}
private synchronized ClientHandlerTestSetup setupClientHandler() throws IOException {
PipedInputStream inputPipe = new PipedInputStream();
PipedOutputStream outputPipe = new PipedOutputStream();
inputPipe.connect(outputPipe);
ByteArrayOutputStream fromClientHandler = new ByteArrayOutputStream();
Socket mockClient = mock(Socket.class);
when(mockClient.getOutputStream()).thenReturn(fromClientHandler);
when(mockClient.getInputStream()).thenReturn(inputPipe);
when(mockClient.getInetAddress()).thenReturn(null);
VirtualView mockView = mock(VirtualView.class);
ControllerInterface mockController = mock(ControllerInterface.class);
ClientHandler clientHandler = new ClientHandler(mockClient);
Thread clientHandlerThread = new Thread(clientHandler, "testedClientHandler");
clientHandlerThread.start();
clientHandler.setOwner(mockView);
clientHandler.setController(mockController);
ObjectOutputStream toClientHandler = new ObjectOutputStream(outputPipe);
return new ClientHandlerTestSetup(clientHandler, toClientHandler, mockController);
}
private record ClientHandlerTestSetup(ClientHandler clientHandler, ObjectOutputStream toClientHandler, ControllerInterface controller) {}
</code>
@Test
public synchronized void placeMsgTest() throws Exception {
ClientHandlerTestSetup setup = setupClientHandler();
ObjectOutputStream toClientHandler = setup.toClientHandler();
ControllerInterface mockController = setup.controller();
LightPlacement fakePlacement = new LightPlacement(new Position(0, 0), new LightCard(0), CardFace.FRONT);
ClientMsg placeMsg = new PlaceMsg(fakePlacement);
toClientHandler.writeObject(placeMsg);
toClientHandler.flush();
Thread.sleep(10);
verify(mockController, times(1)).place(fakePlacement);
}
private synchronized ClientHandlerTestSetup setupClientHandler() throws IOException {
PipedInputStream inputPipe = new PipedInputStream();
PipedOutputStream outputPipe = new PipedOutputStream();
inputPipe.connect(outputPipe);
ByteArrayOutputStream fromClientHandler = new ByteArrayOutputStream();
Socket mockClient = mock(Socket.class);
when(mockClient.getOutputStream()).thenReturn(fromClientHandler);
when(mockClient.getInputStream()).thenReturn(inputPipe);
when(mockClient.getInetAddress()).thenReturn(null);
VirtualView mockView = mock(VirtualView.class);
ControllerInterface mockController = mock(ControllerInterface.class);
ClientHandler clientHandler = new ClientHandler(mockClient);
Thread clientHandlerThread = new Thread(clientHandler, "testedClientHandler");
clientHandlerThread.start();
clientHandler.setOwner(mockView);
clientHandler.setController(mockController);
ObjectOutputStream toClientHandler = new ObjectOutputStream(outputPipe);
return new ClientHandlerTestSetup(clientHandler, toClientHandler, mockController);
}
private record ClientHandlerTestSetup(ClientHandler clientHandler, ObjectOutputStream toClientHandler, ControllerInterface controller) {}
New contributor
Samuele is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.