Add unit test to verify concurrency issue #1461

References pr #75
This commit is contained in:
Andreas Dangel
2016-03-10 20:01:59 +01:00
parent 573186be69
commit 54ce3036b2
2 changed files with 124 additions and 0 deletions

View File

@ -0,0 +1,109 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.processor;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Assert;
import org.junit.Test;
import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.ReportListener;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.RuleSetFactory;
import net.sourceforge.pmd.RuleViolation;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.rule.AbstractRule;
import net.sourceforge.pmd.renderers.Renderer;
import net.sourceforge.pmd.stat.Metric;
import net.sourceforge.pmd.util.datasource.DataSource;
public class MultiThreadProcessorTest {
@Test
public void testRulesThreadSafety() {
PMDConfiguration configuration = new PMDConfiguration();
configuration.setRuleSets("rulesets/MultiThreadProcessorTest/basic.xml");
configuration.setThreads(2);
List<DataSource> files = new ArrayList<>();
files.add(new StringDataSource("file1-violation.dummy", "ABC"));
files.add(new StringDataSource("file2-foo.dummy", "DEF"));
SimpleReportListener reportListener = new SimpleReportListener();
RuleContext ctx = new RuleContext();
ctx.getReport().addListener(reportListener);
MultiThreadProcessor processor = new MultiThreadProcessor(configuration);
RuleSetFactory ruleSetFactory = new RuleSetFactory();
processor.processFiles(ruleSetFactory, files, ctx, Collections.<Renderer>emptyList());
// if the rule is not executed, then maybe a ConcurrentModificationException happened
Assert.assertEquals("Test rule has not been executed", 2, NotThreadSafeRule.count.get());
// if the violation is not reported, then the rule instances have been shared between the threads
Assert.assertEquals("Missing violation", 1, reportListener.violations.get());
}
private static class StringDataSource implements DataSource {
private final String data;
private final String name;
public StringDataSource(String name, String data) {
this.name = name;
this.data = data;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(data.getBytes("UTF-8"));
}
@Override
public String getNiceFileName(boolean shortNames, String inputFileName) {
return name;
}
}
public static class NotThreadSafeRule extends AbstractRule {
public static AtomicInteger count = new AtomicInteger(0);
private boolean hasViolation; // this variable will be overridden between the threads
@Override
public void apply(List<? extends Node> nodes, RuleContext ctx) {
count.incrementAndGet();
if (ctx.getSourceCodeFilename().contains("violation")) {
hasViolation = true;
} else {
letTheOtherThreadRun(10);
hasViolation = false;
}
letTheOtherThreadRun(100);
if (hasViolation) {
addViolation(ctx, nodes.get(0));
}
}
private void letTheOtherThreadRun(int millis) {
try {
Thread.yield();
Thread.sleep(millis);
} catch (InterruptedException e) {
// ignored
}
}
}
private static class SimpleReportListener implements ReportListener {
public AtomicInteger violations = new AtomicInteger(0);
@Override
public void ruleViolationAdded(RuleViolation ruleViolation) {
violations.incrementAndGet();
}
@Override
public void metricAdded(Metric metric) {
}
}
}

View File

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<ruleset name="Test Ruleset" xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<description>
Ruleset used by test RuleSetReferenceIdTest
</description>
<rule name="NotThreadSafeRule" language="dummy" since="1.0" message="Not thread safe" class="net.sourceforge.pmd.processor.MultiThreadProcessorTest$NotThreadSafeRule"
externalInfoUrl="foo">
<description>Foo</description>
<priority>3</priority>
<example></example>
</rule>
</ruleset>