Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use system properties in Jacoco agent configuration #262

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -48,10 +48,68 @@ public void testSystemProperties() {
system.setProperty("output", "tcpserver"); // no prefix
system.setProperty("jacoco-agent.sessionid", "testid");
Properties config = ConfigLoader.load(
"/org/jacoco/agent/rt/agent-test.properties", system);
"/org/jacoco/agent/rt/internal/agent-test.properties", system);

assertEquals("mbean", config.get("output"));
assertEquals("testid", config.get("sessionid"));
}

}
@Test
public void testEnvironmentVariableReplacement() {
Properties system = new Properties();
system.setProperty("user.home", "/user/home");
system.setProperty("java.version", "1.2.3");

Properties config = ConfigLoader.load(
"/org/jacoco/agent/rt/internal/agent-env-test.properties",
system);

assertEquals("/user/home/coverage/unit-test-agent-1.2.3.exec",
config.get("destfile"));
}

@Test
public void testSystemPropertiesEscpaingDollarCharacter() {
Properties system = new Properties();
system.setProperty("user.home", "/user/gerrit");
system.setProperty("jacoco-agent.replaceproperties", "true");

setSystemPropAndAssertEquals(system, "\\\\${ my test \\{ \\}",
"\\\\${ my test \\{ \\}");
setSystemPropAndAssertEquals(system, "${mytest", "${mytest");
setSystemPropAndAssertEquals(system, "$${user.home}", "$/user/gerrit");
setSystemPropAndAssertEquals(system, "\\${user.home}", "\\/user/gerrit");
setSystemPropAndAssertEquals(system, "${user.home}/test/path",
"/user/gerrit/test/path");
}

@Test
public void testSystemPropertiesNoPropertiesReplacement() {
Properties system = new Properties();
system.setProperty("user.home", "/user/gerrit");
system.setProperty("jacoco-agent.replaceproperties", "false");

setSystemPropAndAssertEquals(system, "$${user.home}", "$${user.home}");
setSystemPropAndAssertEquals(system, "\\${user.home}", "\\${user.home}");
setSystemPropAndAssertEquals(system, "${user.home}/test/path",
"${user.home}/test/path");
}

/**
* @param systemPropertyValue
* Sets <code>system</code>'s &quot;jacoco-agent.destfile&quot;
* in <code>system</code> properties
* @param expectedValue
* <code>expectedValue</code> returned by
* {@link ConfigLoader#load(String, Properties)} for key
* &quot;destfile&quot;
*/
private void setSystemPropAndAssertEquals(Properties system,
String systemPropertyValue, String expectedValue) {
system.setProperty("jacoco-agent.destfile", systemPropertyValue);
Properties config = ConfigLoader.load(
"/org/jacoco/agent/rt/internal/agent-env-test.properties",
system);
assertEquals(expectedValue, config.get("destfile"));
}
}
@@ -0,0 +1,2 @@
destfile=${user.home}/coverage/unit-test-agent-${java.version}.exec
replaceproperties=true
Expand Up @@ -15,6 +15,8 @@
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Internal utility to load runtime configuration from a classpath resource and
Expand Down Expand Up @@ -48,6 +50,37 @@ static Properties load(final String resource, final Properties system) {
}
}

// 3. Perform environment variable replacement
if (Boolean.parseBoolean(result.getProperty("replaceproperties",
"false"))) {
final Pattern replacementPattern = Pattern
.compile("\\$\\{([A-Za-z_0-9.-]+)\\}");
for (final Map.Entry<Object, Object> entry : result.entrySet()) {
final String value = (String) entry.getValue();
final Matcher m = replacementPattern.matcher(value);
if (m.find()) {
final StringBuffer sb = new StringBuffer(value.length() * 2);
int offset = 0;
do {
final String propertyName = m.group(1);
if (propertyName != null) {
sb.append(value, offset, m.start());
// replace match by system property
sb.append(system.getProperty(propertyName, ""));
} else {
// keep original string
sb.append(value, offset, m.end());
}
offset = m.end();
} while (m.find());
if (offset < value.length()) {
sb.append(value, offset, value.length());
}
entry.setValue(sb.toString());
}
}
}

return result;
}

Expand Down
2 changes: 1 addition & 1 deletion org.jacoco.build/pom.xml
Expand Up @@ -515,7 +515,7 @@
</goals>
<configuration>
<target>
<fileset dir="${basedir}" includes="**/*.java,**/*.xml,**/*.bsh" excludes="target/**,.idea/**,nb-configuration.xml" id="missinglicense.fileset">
<fileset dir="${basedir}" includes="**/*.java,**/*.xml,**/*.bsh" excludes="bin/**,target/**,.idea/**,nb-configuration.xml" id="missinglicense.fileset">
<not>
<and>
<contains text="Copyright (c) 2009, 2014 Mountainminds GmbH &amp; Co. KG and Contributors"/>
Expand Down
40 changes: 38 additions & 2 deletions org.jacoco.doc/docroot/doc/agent.html
Expand Up @@ -73,7 +73,7 @@ <h1>Java Agent</h1>
<tbody>
<tr>
<td><code>destfile</code></td>
<td>Path to the output file for execution data.</td>
<td>Path to the output file for execution data. See also <code>replaceproperties</code> enabling system property replacement.</td>
<td><code>jacoco.exec</code></td>
</tr>
<tr>
Expand Down Expand Up @@ -145,7 +145,9 @@ <h1>Java Agent</h1>
<td>Output method to use for writing coverage data. Valid options are:
<ul>
<li><code>file</code>: At VM termination execution data is written to
the file specified in the <code>destfile</code> attribute.</li>
the file specified in the <code>destfile</code> attribute. See
also <code>replaceproperties</code> enabling system property
replacement.</li>
<li><code>tcpserver</code>: The agent listens for incoming connections
on the TCP port specified by the <code>address</code> and
<code>port</code> attribute. Execution data is written to this
Expand Down Expand Up @@ -197,6 +199,16 @@ <h1>Java Agent</h1>
</td>
<td><code>false</code></td>
</tr>
<tr>
<td><code>replaceproperties</code></td>
<td>If set to <code>true</code> the agent replaces
<code>${system-property-name}</code> occurrences by the value of Java
system property with key &quot;system-property-name&quot;. If the
property does not exist an empty string is used. Introduced in version 0.7.3.
Also see section about replacing system properties below.
</td>
<td><code>false</code></td>
</tr>
</tbody>
</table>

Expand All @@ -211,6 +223,30 @@ <h2>Security Consideration for Remote Agent Control</h2>
application might be revealed or DOS attacks are possible.
</p>

<h2>Replacing system properties in Agent configuration</h2>

<p>
Example file <code>jacoco-agent.properties</code> for the agent's
<code>destfile</code>:

<pre><code>
replaceproperties=true
destfile=${user.home}/coverage-data/coverage.exec
</code></pre>

By default the replacement feature is disabled. The first line in the
example above enables it. Once enabled replacement is applied to all
Jacoco agent properties. Java's system properties can be used to override
the compile time configuration by adding
<code>-Djacoco-agent.replacementproperties=true</code> or
<code>-Djacoco-agent.destfile=${java.io.tempdir}/coverage.exec</code>
to Java's command line.<br/>
A regular expression <code>\$\{[A-Za-z_0-9.-]+\}</code> is used to
recognize and replace all occurrences. No escaping mechanism has been
implemented because backslash &quot;\&quot; is a path separator on Windows
and dollar &quot;$&quot; occurs in filenames of anonymous or inner classes.
</p>

</div>
<div class="footer">
<span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>
Expand Down