Skip to content

Commit

Permalink
[FIXED JENKINS-31258]
Browse files Browse the repository at this point in the history
- Unknown test plug-ins can now specify the path to their reports directory via the Maven project property jenkins.<execution-id>.reportsDirectory. Relative paths are resolved against the project's base directory.
- Unit test for the above capability.
- Fixed a compilation failure that was apparently caused an extraneous (and inconsistent!) Unicode right-apostrophe character instead of a single quote in Messages.properties
  • Loading branch information
demonfiddler committed Nov 11, 2015
1 parent 59eb555 commit bb25b85
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 31 deletions.
65 changes: 54 additions & 11 deletions src/main/java/hudson/maven/reporters/TestMojo.java
Expand Up @@ -13,6 +13,7 @@
import org.apache.maven.project.MavenProject;
import org.apache.tools.ant.types.FileSet;
import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;

import com.google.common.base.Function;
import com.google.common.collect.Iterators;
Expand Down Expand Up @@ -167,21 +168,34 @@ public boolean canRunTests(MojoInfo mojo) {
}

@CheckForNull public Iterable<File> getReportFiles(MavenProject pom, MojoInfo mojo) throws ComponentConfigurationException {
File reportsDir = getReportsDirectory(pom, mojo);
if (reportsDir != null && reportsDir.exists())
return getReportFiles(reportsDir, getFileSet(reportsDir));

return null;
}

/**
* Returns the location of test reports created by the specified MOJO.
* @param pom The project model.
* @param mojo The MOJO.
* @return The directory containing the test reports.
* @throws ComponentConfigurationException if unable to retrieve the report directory from the MOJO configuration.
*/
protected File getReportsDirectory(MavenProject pom, MojoInfo mojo) throws ComponentConfigurationException {
// [JENKINS-31258] Allow unknown MOJOs to contribute test results in arbitrary locations by setting a Maven property.
String reportsDirectoryOverride = getReportsDirectoryOverride(mojo);
if (reportsDirectoryOverride != null)
return mojo.expressionEvaluator.alignToBaseDirectory(new File(reportsDirectoryOverride));

if (this.reportDirectoryConfigKey != null) {
File reportsDir = mojo.getConfigurationValue(this.reportDirectoryConfigKey, File.class);
if (reportsDir != null && reportsDir.exists()) {
return getReportFiles(reportsDir, getFileSet(reportsDir));
}

if (reportsDir != null)
return reportsDir;
}

// some plugins just default to this:
File reportsDir = new File(pom.getBuild().getDirectory(), "surefire-reports");
if (reportsDir.exists()) {
return getReportFiles(reportsDir, getFileSet(reportsDir));
}

return null;
return new File(pom.getBuild().getDirectory(), "surefire-reports");
}

private Iterable<File> getReportFiles(final File baseDir, FileSet set) {
Expand Down Expand Up @@ -231,12 +245,41 @@ public static TestMojo lookup(String artifactId, String groupId, String goal) {

public static TestMojo lookup(MojoInfo mojo) {
TestMojo testMojo = lookup(mojo.pluginName.groupId, mojo.pluginName.artifactId, mojo.getGoal());

if (testMojo == null && getReportsDirectoryOverride(mojo) != null) {
testMojo = FALLBACK;
}

if (testMojo != null && testMojo.canRunTests(mojo)) {
return testMojo;
}

return null;
}


/**
* For an unknown test-capable MOJO, returns the path to its reports directory as configured by a Maven property.
* @param mojo An unknown MOJO.
* @return the value of the expression <code>${jenkins.&lt;mojo-execution-id&gt;.reportsDirectory}</code>.
*/
private static String getReportsDirectoryOverride(MojoInfo mojo) {
// Validity of the override property should be constrained to "test" and "integration-test" phases but there seems to be no
// way to check this, as MojoExecution.getLifecyclePhase() (added 2009-05-12) causes tests to throw NoSuchMethodError!!!
// So, we're obliged to assume that the property is configured for a valid test life cycle phase.
// String phase = mojo.mojoExecution.getLifecyclePhase();
// if ("test".equals(phase) || "integration-test".equals(phase)) {
try {
String reportsDirExpr = "${jenkins." + mojo.mojoExecution.getExecutionId() + ".reportsDirectory}";
Object result = mojo.expressionEvaluator.evaluate(reportsDirExpr);
if (result != null && !result.equals(reportsDirExpr) && !result.toString().trim().isEmpty())
return result.toString().trim();
} catch (ExpressionEvaluationException e) {
// Ignore evaluation exceptions.
}
// }
return null;
}

static class Key {
private String artifactId;
private String groupId;
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/hudson/maven/Messages.properties
Expand Up @@ -55,7 +55,7 @@ MavenProbeAction.DisplayName=Monitor Maven Process
MavenProcessFactory.ClassWorldsNotFound=No classworlds*.jar found in {0} -- Is this a valid maven directory?

MavenRedeployer.DisplayName=Deploy to Maven repository
MavenVersionCallable.MavenHomeDoesntExist=Maven Home {0} doesn\u2019t exist
MavenVersionCallable.MavenHomeDoesntExist=Maven Home {0} doesn't exist
MavenVersionCallable.MavenHomeIsNotDirectory=Maven Home {0} is not a directory
ProcessCache.Reusing=Reusing existing maven process

Expand Down
47 changes: 28 additions & 19 deletions src/test/java/hudson/maven/MojoInfoBuilder.java
Expand Up @@ -19,6 +19,19 @@ public class MojoInfoBuilder {
private String artifactId;
private String goalName;
private String version = "1.0";
private String executionId;
private ExpressionEvaluator evaluator = new ExpressionEvaluator() {
@Override
public Object evaluate(String expression) {
return expression;
}

@Override
public File alignToBaseDirectory(File file) {
return file;
}
};

private Map<String, String> configValues = new HashMap<String, String>();
private long startTime = System.currentTimeMillis();

Expand All @@ -34,7 +47,7 @@ private MojoInfoBuilder(String groupId, String artifactId, String goalName) {

public MojoInfoBuilder copy() {
MojoInfoBuilder copy = new MojoInfoBuilder(this.groupId, this.artifactId, this.goalName)
.version(this.version);
.version(this.version).executionId(this.executionId).evaluator(this.evaluator);
copy.configValues.putAll(this.configValues);
return copy;
}
Expand All @@ -44,12 +57,22 @@ public MojoInfoBuilder version(String version) {
return this;
}

public MojoInfoBuilder executionId(String executionId) {
this.executionId = executionId;
return this;
}

public MojoInfoBuilder evaluator(ExpressionEvaluator evaluator) {
this.evaluator = evaluator;
return this;
}

public MojoInfoBuilder startTime(long startTime) {
this.startTime = startTime;
return this;
}

public MojoInfoBuilder configValue(String key,String value) {
public MojoInfoBuilder configValue(String key, String value) {
configValues.put(key, value);
return this;
}
Expand All @@ -64,28 +87,14 @@ public MojoInfo build() {
mojoDescriptor.setPluginDescriptor(pluginDescriptor);
mojoDescriptor.setGoal(goalName);

MojoExecution mojoExecution = new MojoExecution(mojoDescriptor);
MojoExecution mojoExecution = new MojoExecution(mojoDescriptor, executionId);

PlexusConfiguration configuration = new DefaultPlexusConfiguration("configuration");
for (Map.Entry<String, String> e : this.configValues.entrySet()) {
configuration.addChild(e.getKey(),e.getValue());
configuration.addChild(e.getKey(), e.getValue());
}

ExpressionEvaluator evaluator = new ExpressionEvaluator() {
@Override
public Object evaluate(String expression) {
return expression;
}

@Override
public File alignToBaseDirectory(File file) {
return file;
}
};

MojoInfo info = new MojoInfo(mojoExecution, null, configuration, evaluator, startTime);
MojoInfo info = new MojoInfo(mojoExecution, null, configuration, evaluator, startTime);
return info;
}


}
67 changes: 67 additions & 0 deletions src/test/java/hudson/maven/reporters/TestMojoTest.java
Expand Up @@ -15,9 +15,12 @@

import org.apache.maven.model.Build;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
import org.junit.Test;
import org.jvnet.hudson.test.Bug;
import org.jvnet.hudson.test.Issue;

public class TestMojoTest {

Expand Down Expand Up @@ -219,4 +222,68 @@ private static interface ScalatestPluginTest {
public void run(MojoInfoBuilder mojoBuilder, MavenProject pom,
String testResultsName) throws Exception;
}

@Test
@Issue("JENKINS-31258")
public void testGetReportFilesUnknownTestPlugin() throws Exception {
final String testResultsName = "TEST-some.test.results.xml";

final File baseDir = hudson.Util.createTempDir();
final File targetDir = new File(baseDir, "target");
final File reportsDir = new File(targetDir, "some-test-reports");
assertTrue(reportsDir.mkdirs());

MojoInfoBuilder builder = MojoInfoBuilder.mojoBuilder("com.some", "unknown-test-capable-plugin", "somegoal")
.evaluator(new ExpressionEvaluator() {
@Override
public Object evaluate(String expression) throws ExpressionEvaluationException {
if ("${jenkins.some-test-execution-id.reportsDirectory}".equals(expression))
return "target/some-test-reports";
return expression;
}

@Override
public File alignToBaseDirectory(File path) {
return new File(baseDir, path.getPath());
}
});

MojoInfo nonReportingMojo = builder.executionId("some-non-test-execution-id").build();
TestMojo testMojo = TestMojo.lookup(nonReportingMojo);
assertNull("misreported an unknown, unconfigured MOJO as test capable", testMojo);

MojoInfo reportingMojo = builder.executionId("some-test-execution-id").build();
testMojo = TestMojo.lookup(reportingMojo);
assertNotNull("failed to recognize correctly configured unknown test capable MOJO", testMojo);

MavenProject pom = mock(MavenProject.class);
when(pom.getBasedir()).thenReturn(baseDir);

Build build = mock(Build.class);
when(build.getDirectory()).thenReturn(targetDir.getAbsolutePath());
when(pom.getBuild()).thenReturn(build);

assertEquals("test mojo returned incorrect reports directory", new File(baseDir, "target/some-test-reports"),
testMojo.getReportsDirectory(pom, reportingMojo));

File testResults = new File(reportsDir, testResultsName);
try {
FileWriter fw = new FileWriter(testResults, false);
fw.write("this is a fake surefire reports output file");
fw.close();

Iterable<File> files = testMojo.getReportFiles(pom, reportingMojo);
assertNotNull("no report files returned", files);

boolean found = false;
for (File file : files) {
assertEquals(testResultsName, file.getName());
found = true;
}
assertTrue("report file not found", found);
} finally {
hudson.Util.deleteRecursive(baseDir);
}
}

}

0 comments on commit bb25b85

Please sign in to comment.