1/*******************************************************************************
2 * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *    Marc R. Hoffmann - initial API and implementation
10 *
11 *******************************************************************************/
12package org.jacoco.cli.internal.commands;
13
14import static org.junit.Assert.assertTrue;
15import static org.junit.Assert.fail;
16
17import java.io.File;
18import java.io.IOException;
19import java.net.InetAddress;
20import java.net.ServerSocket;
21import java.net.Socket;
22
23import org.jacoco.cli.internal.CommandTestBase;
24import org.jacoco.core.runtime.IRemoteCommandVisitor;
25import org.jacoco.core.runtime.RemoteControlReader;
26import org.jacoco.core.runtime.RemoteControlWriter;
27import org.junit.After;
28import org.junit.Rule;
29import org.junit.Test;
30import org.junit.rules.TemporaryFolder;
31
32/**
33 * Unit tests for {@link Dump}.
34 */
35public class DumpTest extends CommandTestBase {
36
37	@Rule
38	public TemporaryFolder tmp = new TemporaryFolder();
39
40	private ServerSocket serverSocket;
41
42	@After
43	public void after() throws IOException {
44		if (serverSocket != null) {
45			serverSocket.close();
46		}
47	}
48
49	@Test
50	public void should_print_usage_when_no_argument_is_given()
51			throws Exception {
52		execute("dump");
53		assertFailure();
54		assertContains("Option \"--destfile\" is required", err);
55		assertContains("java -jar jacococli.jar dump [--address <address>]",
56				err);
57	}
58
59	@Test
60	public void should_write_dump() throws Exception {
61
62		File execfile = new File(tmp.getRoot(), "jacoco.exec");
63		int port = startMockServer();
64
65		execute("dump", "--destfile", execfile.getAbsolutePath(), "--port",
66				String.valueOf(port));
67
68		assertOk();
69		assertContains("[INFO] Connecting to ", out);
70		assertContains("[INFO] Writing execution data to "
71				+ execfile.getAbsolutePath(), out);
72		assertTrue(execfile.exists());
73	}
74
75	@Test
76	public void should_log_connection_error_when_retry_is_specified()
77			throws Exception {
78
79		File execfile = new File(tmp.getRoot(), "jacoco.exec");
80		int port = unusedPort();
81
82		try {
83			execute("dump", "--destfile", execfile.getAbsolutePath(), "--port",
84					String.valueOf(port), "--retry", "1");
85			fail("IOException expected");
86		} catch (IOException ignore) {
87		}
88
89		assertContains("[WARN] Connection refused", err);
90	}
91
92	private int startMockServer() throws IOException {
93		serverSocket = new ServerSocket(0, 0, InetAddress.getByName(null));
94		new Thread() {
95			@Override
96			public void run() {
97				try {
98					serveRequest(serverSocket.accept());
99				} catch (IOException e) {
100					throw new RuntimeException(e);
101				}
102			}
103		}.start();
104		return serverSocket.getLocalPort();
105	}
106
107	private void serveRequest(Socket socket) throws IOException {
108		final RemoteControlWriter writer = new RemoteControlWriter(
109				socket.getOutputStream());
110		final RemoteControlReader reader = new RemoteControlReader(
111				socket.getInputStream());
112		reader.setRemoteCommandVisitor(new IRemoteCommandVisitor() {
113
114			public void visitDumpCommand(boolean dump, boolean reset)
115					throws IOException {
116				writer.sendCmdOk();
117			}
118		});
119		while (reader.read()) {
120		}
121	}
122
123	private int unusedPort() throws IOException {
124		final ServerSocket serverSocket = new ServerSocket(0, 0,
125				InetAddress.getByName(null));
126		final int port = serverSocket.getLocalPort();
127		serverSocket.close();
128		return port;
129	}
130
131}
132