blob: 591d032f10a1b287b4b7e723903a7f7cd98384f5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Marc R. Hoffmann - initial API and implementation
*
*******************************************************************************/
package org.jacoco.core.tools;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.io.InputStream;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.jacoco.core.data.SessionInfo;
import org.jacoco.core.runtime.IRemoteCommandVisitor;
import org.jacoco.core.runtime.RemoteControlReader;
import org.jacoco.core.runtime.RemoteControlWriter;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
/**
* Unit tests for {@link ExecDumpClient}.
*/
public class ExecDumpClientTest {
private ExecDumpClient client;
private List<String> callbacks;
private boolean dumpRequested;
private boolean resetRequested;
private ServerSocket server;
@Rule
public ExpectedException exception = ExpectedException.none();
@Before
public void setup() {
callbacks = new ArrayList<String>();
client = new ExecDumpClient() {
@Override
protected void onConnecting(InetAddress address, int port) {
callbacks.add("onConnecting");
}
@Override
protected void onConnectionFailure(IOException exception) {
callbacks.add("onConnectionFailure");
}
};
}
@After
public void teardown() throws IOException {
if (server != null) {
server.close();
}
}
@Test
public void testNoRetries() throws IOException {
try {
client.dump((String) null, getFreePort());
fail("ConnectException expected");
} catch (ConnectException e) {
// expected
}
assertEquals(Arrays.asList("onConnecting"), callbacks);
}
@Test
public void testWithRetries() throws IOException {
client.setRetryCount(3);
client.setRetryDelay(0);
try {
client.dump((String) null, getFreePort());
fail("ConnectException expected");
} catch (ConnectException e) {
// expected
}
assertEquals(Arrays.asList( // Initial attempt
"onConnecting",
// 1. Retry
"onConnectionFailure", "onConnecting",
// 2. Retry
"onConnectionFailure", "onConnecting",
// 3. Retry
"onConnectionFailure", "onConnecting")
, callbacks);
}
@Test
public void testDump() throws IOException {
int port = createExecServer();
ExecFileLoader loader = client.dump((String) null, port);
assertTrue(dumpRequested);
assertFalse(resetRequested);
List<SessionInfo> infos = loader.getSessionInfoStore().getInfos();
assertEquals(1, infos.size());
assertEquals("TestId", infos.get(0).getId());
}
@Test
public void testReset() throws IOException {
int port = createExecServer();
client.setDump(false);
client.setReset(true);
client.dump((String) null, port);
assertFalse(dumpRequested);
assertTrue(resetRequested);
}
@Test
public void should_throw_IOException_when_server_closes_connection_without_response()
throws IOException {
exception.expect(IOException.class);
exception.expectMessage("Socket closed unexpectedly.");
int port = createNopServer();
client.dump((String) null, port);
}
private int getFreePort() throws IOException {
final ServerSocket server = new ServerSocket(0, 0,
InetAddress.getByName(null));
final int port = server.getLocalPort();
server.close();
return port;
}
private int createExecServer() throws IOException {
server = new ServerSocket(0, 0, InetAddress.getByName(null));
new Thread(new Runnable() {
public void run() {
try {
handleConnection(server.accept());
} catch (IOException e) {
// ignore
}
}
}).start();
return server.getLocalPort();
}
private void handleConnection(Socket socket) throws IOException {
final RemoteControlWriter writer = new RemoteControlWriter(
socket.getOutputStream());
final RemoteControlReader reader = new RemoteControlReader(
socket.getInputStream());
reader.setRemoteCommandVisitor(new IRemoteCommandVisitor() {
public void visitDumpCommand(boolean dump, boolean reset)
throws IOException {
dumpRequested = dump;
resetRequested = reset;
if (dump) {
writer.visitSessionInfo(
new SessionInfo("TestId", 100, 200));
}
writer.sendCmdOk();
}
});
reader.read();
}
private int createNopServer() throws IOException {
server = new ServerSocket(0, 0, InetAddress.getByName(null));
new Thread(new Runnable() {
public void run() {
try {
Socket socket = server.accept();
InputStream in = socket.getInputStream();
// Read Header:
in.read();
in.read();
in.read();
in.read();
in.read();
// Read Dump Command:
in.read();
in.read();
in.read();
// Then just close connection without any response:
socket.close();
} catch (IOException e) {
// ignore
}
}
}).start();
return server.getLocalPort();
}
}