diff options
author | Simon Brandhof <simon.brandhof@gmail.com> | 2011-06-17 18:01:48 +0200 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@gmail.com> | 2011-06-17 18:01:57 +0200 |
commit | 9a7fb4969d31cf0b5f5c3dbafcc19d39b9d86016 (patch) | |
tree | 226688fc6a941bdc1e86290446ce016f40f7f3bb | |
parent | c973498cfec4ff8e59ac33e9c9fb150a71ef828a (diff) | |
download | sonarqube-9a7fb4969d31cf0b5f5c3dbafcc19d39b9d86016.tar.gz sonarqube-9a7fb4969d31cf0b5f5c3dbafcc19d39b9d86016.zip |
SONAR-2505 support tracking of violations on dry runs
26 files changed, 681 insertions, 728 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java index 08817c0ac0b..c14be8d3310 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java @@ -214,10 +214,12 @@ public class CorePlugin extends SonarPlugin { extensions.add(DirectoriesDecorator.class); extensions.add(FilesDecorator.class); extensions.add(CloseReviewsDecorator.class); + extensions.add(ReferenceAnalysis.class); // time machine extensions.add(TendencyDecorator.class); extensions.add(VariationDecorator.class); + extensions.add(ViolationTrackingDecorator.class); extensions.add(ViolationPersisterDecorator.class); extensions.add(NewViolationsDecorator.class); extensions.add(TimeMachineConfigurationPersister.class); diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ReferenceAnalysis.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ReferenceAnalysis.java new file mode 100644 index 00000000000..4a04c1ec810 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ReferenceAnalysis.java @@ -0,0 +1,55 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.timemachine; + +import org.sonar.api.BatchExtension; +import org.sonar.api.database.DatabaseSession; +import org.sonar.api.database.model.ResourceModel; +import org.sonar.api.database.model.RuleFailureModel; +import org.sonar.api.database.model.Snapshot; +import org.sonar.api.resources.Resource; + +import javax.persistence.Query; +import java.util.Collections; +import java.util.List; + +public class ReferenceAnalysis implements BatchExtension { + + private DatabaseSession session; + + public ReferenceAnalysis(DatabaseSession session) { + this.session = session; + } + + public List<RuleFailureModel> getViolations(Resource resource) { + Snapshot snapshot = getSnapshot(resource); + if (snapshot != null) { + return session.getResults(RuleFailureModel.class, "snapshotId", snapshot.getId()); + } + return Collections.emptyList(); + } + + Snapshot getSnapshot(Resource resource) { + Query query = session.createQuery("from " + Snapshot.class.getSimpleName() + " s where s.last=true and s.resourceId=(select r.id from " + + ResourceModel.class.getSimpleName() + " r where r.key=:key)"); + query.setParameter("key", resource.getEffectiveKey()); + return session.getSingleResult(query, null); + } +} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/SourceChecksum.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/SourceChecksum.java new file mode 100644 index 00000000000..8d6c327e749 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/SourceChecksum.java @@ -0,0 +1,52 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.timemachine; + +import com.google.common.collect.Lists; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang.StringUtils; + +import java.util.List; + +public final class SourceChecksum { + + private static final String SPACE_CHARS = "\t\n\r "; + + private SourceChecksum() { + // only static methods + } + + public static List<String> lineChecksumsOfFile(String file) { + List<String> result = Lists.newArrayList(); + if (file != null) { + String[] lines = file.split("\r?\n|\r", -1); + for (String line : lines) { + result.add(lineChecksum(line)); + } + } + return result; + } + + public static String lineChecksum(String line) { + String reducedLine = StringUtils.replaceChars(line, SPACE_CHARS, ""); + return DigestUtils.md5Hex(reducedLine); + } + +} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecorator.java index b14e7649670..43f7887ca33 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecorator.java @@ -19,215 +19,86 @@ */ package org.sonar.plugins.core.timemachine; -import java.util.Collection; -import java.util.Collections; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.lang.ObjectUtils; -import org.apache.commons.lang.StringUtils; -import org.sonar.api.batch.Decorator; -import org.sonar.api.batch.DecoratorBarriers; -import org.sonar.api.batch.DecoratorContext; -import org.sonar.api.batch.DependedUpon; -import org.sonar.api.batch.DependsUpon; +import org.sonar.api.batch.*; +import org.sonar.api.database.DatabaseSession; import org.sonar.api.database.model.RuleFailureModel; -import org.sonar.api.database.model.SnapshotSource; +import org.sonar.api.database.model.Snapshot; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleFinder; import org.sonar.api.rules.Violation; -import org.sonar.batch.components.PastViolationsLoader; -import org.sonar.batch.index.ViolationPersister; - -import com.google.common.collect.LinkedHashMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; +import org.sonar.batch.index.ResourcePersister; import org.sonar.core.NotDryRun; +import java.util.List; + @NotDryRun -@DependsUpon({ DecoratorBarriers.END_OF_VIOLATIONS_GENERATION, DecoratorBarriers.START_VIOLATION_TRACKING }) @DependedUpon(DecoratorBarriers.END_OF_VIOLATION_TRACKING) public class ViolationPersisterDecorator implements Decorator { - /** - * Those chars would be ignored during generation of checksums. - */ - private static final String SPACE_CHARS = "\t\n\r "; - - private PastViolationsLoader pastViolationsLoader; - private ViolationPersister violationPersister; + private ViolationTrackingDecorator tracker; + private ResourcePersister persister; + private RuleFinder ruleFinder; + private DatabaseSession session; - List<String> checksums; - - public ViolationPersisterDecorator(PastViolationsLoader pastViolationsLoader, ViolationPersister violationPersister) { - this.pastViolationsLoader = pastViolationsLoader; - this.violationPersister = violationPersister; + public ViolationPersisterDecorator(ViolationTrackingDecorator tracker, ResourcePersister persister, RuleFinder ruleFinder, DatabaseSession session) { + this.tracker = tracker; + this.persister = persister; + this.ruleFinder = ruleFinder; + this.session = session; } public boolean shouldExecuteOnProject(Project project) { return true; } - public void decorate(Resource resource, DecoratorContext context) { - if (context.getViolations().isEmpty()) { - return; - } - // Load new violations - List<Violation> newViolations = context.getViolations(); - - // Load past violations - List<RuleFailureModel> pastViolations = pastViolationsLoader.getPastViolations(resource); - - // Load current source code and calculate checksums for each line - checksums = getChecksums(pastViolationsLoader.getSource(resource)); - - // Map new violations with old ones - Map<Violation, RuleFailureModel> violationMap = mapViolations(newViolations, pastViolations); - - for (Violation newViolation : newViolations) { - String checksum = getChecksumForLine(checksums, newViolation.getLineId()); - violationPersister.saveViolation(context.getProject(), newViolation, violationMap.get(newViolation), checksum); - } - violationPersister.commit(); - // Clear cache - checksums.clear(); - } - - Map<Violation, RuleFailureModel> mapViolations(List<Violation> newViolations, List<RuleFailureModel> pastViolations) { - Map<Violation, RuleFailureModel> violationMap = new IdentityHashMap<Violation, RuleFailureModel>(); - - Multimap<Integer, RuleFailureModel> pastViolationsByRule = LinkedHashMultimap.create(); - for (RuleFailureModel pastViolation : pastViolations) { - pastViolationsByRule.put(pastViolation.getRuleId(), pastViolation); - } - - // Try first to match violations on same rule with same line and with same checkum (but not necessarily with same message) - for (Violation newViolation : newViolations) { - mapViolation(newViolation, - findPastViolationWithSameLineAndChecksum(newViolation, pastViolationsByRule.get(newViolation.getRule().getId())), - pastViolationsByRule, violationMap); - } - - // If each new violation matches an old one we can stop the matching mechanism - if (violationMap.size() != newViolations.size()) { - - // Try then to match violations on same rule with same message and with same checkum - for (Violation newViolation : newViolations) { - if (isNotAlreadyMapped(newViolation, violationMap)) { - mapViolation(newViolation, - findPastViolationWithSameChecksumAndMessage(newViolation, pastViolationsByRule.get(newViolation.getRule().getId())), - pastViolationsByRule, violationMap); - } - } - - // Try then to match violations on same rule with same line and with same message - for (Violation newViolation : newViolations) { - if (isNotAlreadyMapped(newViolation, violationMap)) { - mapViolation(newViolation, - findPastViolationWithSameLineAndMessage(newViolation, pastViolationsByRule.get(newViolation.getRule().getId())), - pastViolationsByRule, violationMap); - } - } - } - - return violationMap; - } - - private boolean isNotAlreadyMapped(Violation newViolation, Map<Violation, RuleFailureModel> violationMap) { - return violationMap.get(newViolation) == null; - } - - private RuleFailureModel findPastViolationWithSameLineAndMessage(Violation newViolation, Collection<RuleFailureModel> pastViolations) { - for (RuleFailureModel pastViolation : pastViolations) { - if (isSameLine(newViolation, pastViolation) && isSameMessage(newViolation, pastViolation)) { - return pastViolation; - } - } - return null; - } - - private RuleFailureModel findPastViolationWithSameChecksumAndMessage(Violation newViolation, Collection<RuleFailureModel> pastViolations) { - for (RuleFailureModel pastViolation : pastViolations) { - if (isSameChecksum(newViolation, pastViolation) && isSameMessage(newViolation, pastViolation)) { - return pastViolation; - } - } - return null; + @DependsUpon + public Class dependsOnTracker() { + return ViolationTrackingDecorator.class; } - private RuleFailureModel findPastViolationWithSameLineAndChecksum(Violation newViolation, Collection<RuleFailureModel> pastViolations) { - for (RuleFailureModel pastViolation : pastViolations) { - if (isSameLine(newViolation, pastViolation) && isSameChecksum(newViolation, pastViolation)) { - return pastViolation; - } - } - return null; - } - - private boolean isSameChecksum(Violation newViolation, RuleFailureModel pastViolation) { - return pastViolation.getChecksum() != null - && StringUtils.equals(pastViolation.getChecksum(), getChecksumForLine(checksums, newViolation.getLineId())); + public void decorate(Resource resource, DecoratorContext context) { + saveViolations(context.getProject(), context.getViolations()); } - private boolean isSameLine(Violation newViolation, RuleFailureModel pastViolation) { - if (pastViolation.getLine() == null && newViolation.getLineId() == null) { - return true; + void saveViolations(Project project, List<Violation> violations) { + for (Violation violation : violations) { + RuleFailureModel referenceViolation = tracker.getReferenceViolation(violation); + save(project, violation, referenceViolation); } - return ObjectUtils.equals(pastViolation.getLine(), newViolation.getLineId()); + session.commit(); } - private boolean isSameMessage(Violation newViolation, RuleFailureModel pastViolation) { - return StringUtils.equals(RuleFailureModel.abbreviateMessage(newViolation.getMessage()), pastViolation.getMessage()); - } + public void save(Project project, Violation violation, RuleFailureModel referenceViolation) { + Snapshot snapshot = persister.saveResource(project, violation.getResource()); - private void mapViolation(Violation newViolation, RuleFailureModel pastViolation, - Multimap<Integer, RuleFailureModel> pastViolationsByRule, Map<Violation, RuleFailureModel> violationMap) { - if (pastViolation != null) { - pastViolationsByRule.remove(newViolation.getRule().getId(), pastViolation); - violationMap.put(newViolation, pastViolation); + RuleFailureModel model = createModel(violation); + if (referenceViolation != null) { + model.setPermanentId(referenceViolation.getPermanentId()); } - } - - /** - * @return checksums, never null - */ - private List<String> getChecksums(SnapshotSource source) { - return source == null || source.getData() == null ? Collections.<String> emptyList() : getChecksums(source.getData()); - } + model.setSnapshotId(snapshot.getId()); + session.saveWithoutFlush(model); - /** - * @param data - * can't be null - */ - static List<String> getChecksums(String data) { - String[] lines = data.split("\r?\n|\r", -1); - List<String> result = Lists.newArrayList(); - for (String line : lines) { - result.add(getChecksum(line)); + if (model.getPermanentId() == null) { + model.setPermanentId(model.getId()); + session.saveWithoutFlush(model); } - return result; + violation.setMessage(model.getMessage());// the message can be changed in the class RuleFailure (truncate + trim) } - static String getChecksum(String line) { - String reducedLine = StringUtils.replaceChars(line, SPACE_CHARS, ""); - return DigestUtils.md5Hex(reducedLine); - } - /** - * @return checksum or null if checksum not exists for line - */ - private String getChecksumForLine(List<String> checksums, Integer line) { - if (line == null || line < 1 || line > checksums.size()) { - return null; - } - return checksums.get(line - 1); + private RuleFailureModel createModel(Violation violation) { + RuleFailureModel model = new RuleFailureModel(); + Rule rule = ruleFinder.findByKey(violation.getRule().getRepositoryKey(), violation.getRule().getKey()); + model.setRuleId(rule.getId()); + model.setPriority(violation.getSeverity()); + model.setLine(violation.getLineId()); + model.setMessage(violation.getMessage()); + model.setCost(violation.getCost()); + model.setChecksum(violation.getChecksum()); + model.setCreatedAt(violation.getCreatedAt()); + model.setSwitchedOff(violation.isSwitchedOff()); + return model; } - - @Override - public String toString() { - return getClass().getSimpleName(); - } - } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationTrackingDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationTrackingDecorator.java new file mode 100644 index 00000000000..bab5ee4a374 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationTrackingDecorator.java @@ -0,0 +1,197 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.timemachine; + +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang.ObjectUtils; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.batch.*; +import org.sonar.api.database.model.RuleFailureModel; +import org.sonar.api.resources.Project; +import org.sonar.api.resources.Resource; +import org.sonar.api.rules.Violation; + +import java.util.Collection; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +@DependsUpon({DecoratorBarriers.END_OF_VIOLATIONS_GENERATION, DecoratorBarriers.START_VIOLATION_TRACKING}) +@DependedUpon(DecoratorBarriers.END_OF_VIOLATION_TRACKING) +public class ViolationTrackingDecorator implements Decorator { + private ReferenceAnalysis referenceAnalysis; + private Map<Violation, RuleFailureModel> referenceViolationsMap = Maps.newIdentityHashMap(); + private SonarIndex index; + private Project project; + + public ViolationTrackingDecorator(Project project, ReferenceAnalysis referenceAnalysis, SonarIndex index) { + this.referenceAnalysis = referenceAnalysis; + this.index = index; + this.project = project; + } + + public boolean shouldExecuteOnProject(Project project) { + return true; + } + + public void decorate(Resource resource, DecoratorContext context) { + referenceViolationsMap.clear(); + + if (!context.getViolations().isEmpty()) { + // Load new violations + List<Violation> newViolations = prepareNewViolations(context); + + // Load reference violations + List<RuleFailureModel> referenceViolations = referenceAnalysis.getViolations(resource); + + // Map new violations with old ones + mapViolations(newViolations, referenceViolations); + } + } + + private List<Violation> prepareNewViolations(DecoratorContext context) { + List<Violation> result = Lists.newArrayList(); + List<String> checksums = SourceChecksum.lineChecksumsOfFile(index.getSource(context.getResource())); + for (Violation violation : context.getViolations()) { + violation.setChecksum(getChecksumForLine(checksums, violation.getLineId())); + result.add(violation); + } + return result; + } + + RuleFailureModel getReferenceViolation(Violation violation) { + return referenceViolationsMap.get(violation); + } + + Map<Violation, RuleFailureModel> mapViolations(List<Violation> newViolations, List<RuleFailureModel> pastViolations) { + Multimap<Integer, RuleFailureModel> pastViolationsByRule = LinkedHashMultimap.create(); + for (RuleFailureModel pastViolation : pastViolations) { + pastViolationsByRule.put(pastViolation.getRuleId(), pastViolation); + } + + // Try first to match violations on same rule with same line and with same checkum (but not necessarily with same message) + for (Violation newViolation : newViolations) { + mapViolation(newViolation, + findPastViolationWithSameLineAndChecksum(newViolation, pastViolationsByRule.get(newViolation.getRule().getId())), + pastViolationsByRule, referenceViolationsMap); + } + + // If each new violation matches an old one we can stop the matching mechanism + if (referenceViolationsMap.size() != newViolations.size()) { + // Try then to match violations on same rule with same message and with same checkum + for (Violation newViolation : newViolations) { + if (isNotAlreadyMapped(newViolation, referenceViolationsMap)) { + mapViolation(newViolation, + findPastViolationWithSameChecksumAndMessage(newViolation, pastViolationsByRule.get(newViolation.getRule().getId())), + pastViolationsByRule, referenceViolationsMap); + } + } + + // Try then to match violations on same rule with same line and with same message + for (Violation newViolation : newViolations) { + if (isNotAlreadyMapped(newViolation, referenceViolationsMap)) { + mapViolation(newViolation, + findPastViolationWithSameLineAndMessage(newViolation, pastViolationsByRule.get(newViolation.getRule().getId())), + pastViolationsByRule, referenceViolationsMap); + } + } + } + return referenceViolationsMap; + } + + private boolean isNotAlreadyMapped(Violation newViolation, Map<Violation, RuleFailureModel> violationMap) { + return !violationMap.containsKey(newViolation); + } + + private RuleFailureModel findPastViolationWithSameLineAndMessage(Violation newViolation, Collection<RuleFailureModel> pastViolations) { + for (RuleFailureModel pastViolation : pastViolations) { + if (isSameLine(newViolation, pastViolation) && isSameMessage(newViolation, pastViolation)) { + return pastViolation; + } + } + return null; + } + + private RuleFailureModel findPastViolationWithSameChecksumAndMessage(Violation newViolation, Collection<RuleFailureModel> pastViolations) { + for (RuleFailureModel pastViolation : pastViolations) { + if (isSameChecksum(newViolation, pastViolation) && isSameMessage(newViolation, pastViolation)) { + return pastViolation; + } + } + return null; + } + + private RuleFailureModel findPastViolationWithSameLineAndChecksum(Violation newViolation, Collection<RuleFailureModel> pastViolations) { + for (RuleFailureModel pastViolation : pastViolations) { + if (isSameLine(newViolation, pastViolation) && isSameChecksum(newViolation, pastViolation)) { + return pastViolation; + } + } + return null; + } + + private boolean isSameChecksum(Violation newViolation, RuleFailureModel pastViolation) { + return pastViolation.getChecksum() != null + && StringUtils.equals(pastViolation.getChecksum(), newViolation.getChecksum()); + } + + private boolean isSameLine(Violation newViolation, RuleFailureModel pastViolation) { + if (pastViolation.getLine() == null && newViolation.getLineId() == null) { + return true; + } + return ObjectUtils.equals(pastViolation.getLine(), newViolation.getLineId()); + } + + private boolean isSameMessage(Violation newViolation, RuleFailureModel pastViolation) { + return StringUtils.equals(RuleFailureModel.abbreviateMessage(newViolation.getMessage()), pastViolation.getMessage()); + } + + private void mapViolation(Violation newViolation, RuleFailureModel pastViolation, + Multimap<Integer, RuleFailureModel> pastViolationsByRule, Map<Violation, RuleFailureModel> violationMap) { + if (pastViolation != null) { + newViolation.setCreatedAt(pastViolation.getCreatedAt()); + newViolation.setSwitchedOff(pastViolation.isSwitchedOff()); + pastViolationsByRule.remove(newViolation.getRule().getId(), pastViolation); + violationMap.put(newViolation, pastViolation); + } else { + newViolation.setCreatedAt(project.getAnalysisDate()); + } + } + + /** + * @return checksum or null if checksum not exists for line + */ + private String getChecksumForLine(List<String> checksums, Integer line) { + if (line == null || line < 1 || line > checksums.size()) { + return null; + } + return checksums.get(line - 1); + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } + +} diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/SourceChecksumTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/SourceChecksumTest.java new file mode 100644 index 00000000000..3c361aa61da --- /dev/null +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/SourceChecksumTest.java @@ -0,0 +1,53 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.timemachine; + +import org.junit.Test; + +import java.util.List; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; + +public class SourceChecksumTest { + /** + * See http://jira.codehaus.org/browse/SONAR-2358 + */ + @Test + public void shouldGenerateCorrectChecksums() { + List<String> encoding = SourceChecksum.lineChecksumsOfFile("Привет Мир"); + assertThat(encoding.size(), is(1)); + assertThat(encoding.get(0), is("5ba3a45e1299ede07f56e5531351be52")); + } + + @Test + public void shouldSplitLinesAndIgnoreSpaces() { + List<String> crlf = SourceChecksum.lineChecksumsOfFile("Hello\r\nWorld"); + List<String> lf = SourceChecksum.lineChecksumsOfFile("Hello\nWorld"); + List<String> cr = SourceChecksum.lineChecksumsOfFile("Hello\rWorld"); + assertThat(crlf.size(), is(2)); + assertThat(crlf.get(0), not(equalTo(crlf.get(1)))); + assertThat(lf, equalTo(crlf)); + assertThat(cr, equalTo(crlf)); + + assertThat(SourceChecksum.lineChecksum("\tvoid method() {\n"), + equalTo(SourceChecksum.lineChecksum(" void method() {"))); + } +} diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest.java index 96702000de6..ae996a82178 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest.java @@ -19,170 +19,70 @@ */ package org.sonar.plugins.core.timemachine; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; - -import java.util.List; -import java.util.Map; - import org.junit.Before; import org.junit.Test; import org.sonar.api.database.model.RuleFailureModel; +import org.sonar.api.database.model.Snapshot; +import org.sonar.api.resources.JavaFile; +import org.sonar.api.resources.Project; import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RulePriority; import org.sonar.api.rules.Violation; +import org.sonar.api.utils.DateUtils; +import org.sonar.batch.index.ResourcePersister; +import org.sonar.core.components.DefaultRuleFinder; +import org.sonar.jpa.test.AbstractDbUnitTestCase; + +import java.util.Arrays; -import com.google.common.collect.Lists; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; -public class ViolationPersisterDecoratorTest { +public class ViolationPersisterDecoratorTest extends AbstractDbUnitTestCase { private ViolationPersisterDecorator decorator; + private Rule rule1 = Rule.create("checkstyle", "com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck", "Check Header"); + private Rule rule2 = Rule.create("checkstyle", "com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck", "Equals Avoid Null"); + private JavaFile javaFile = new JavaFile("org.foo.Bar"); + Project project = new Project("project"); + private ViolationTrackingDecorator tracker; @Before - public void setUp() { - decorator = new ViolationPersisterDecorator(null, null); - } - - /** - * See http://jira.codehaus.org/browse/SONAR-2358 - */ - @Test - public void shouldGenerateCorrectChecksums() { - List<String> encoding = ViolationPersisterDecorator.getChecksums("Привет Мир"); - assertThat(encoding.size(), is(1)); - assertThat(encoding.get(0), is("5ba3a45e1299ede07f56e5531351be52")); - } - - @Test - public void shouldSplitLinesAndIgnoreSpaces() { - List<String> crlf = ViolationPersisterDecorator.getChecksums("Hello\r\nWorld"); - List<String> lf = ViolationPersisterDecorator.getChecksums("Hello\nWorld"); - List<String> cr = ViolationPersisterDecorator.getChecksums("Hello\rWorld"); - assertThat(crlf.size(), is(2)); - assertThat(crlf.get(0), not(equalTo(crlf.get(1)))); - assertThat(lf, equalTo(crlf)); - assertThat(cr, equalTo(crlf)); - - assertThat(ViolationPersisterDecorator.getChecksum("\tvoid method() {\n"), - equalTo(ViolationPersisterDecorator.getChecksum(" void method() {"))); - } - - @Test - public void checksumShouldHaveGreaterPriorityThanLine() { - RuleFailureModel pastViolation1 = newPastViolation("message", 1, 50, "checksum1"); - RuleFailureModel pastViolation2 = newPastViolation("message", 3, 50, "checksum2"); - - Violation newViolation1 = newViolation("message", 3, 50, "checksum1"); - Violation newViolation2 = newViolation("message", 5, 50, "checksum2"); - - Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation1, newViolation2), - Lists.newArrayList(pastViolation1, pastViolation2)); - assertThat(mapping.get(newViolation1), equalTo(pastViolation1)); - assertThat(mapping.get(newViolation2), equalTo(pastViolation2)); - } - - @Test - public void sameRuleAndLineAndChecksumButDifferentMessages() { - Violation newViolation = newViolation("new message", 1, 50, "checksum1"); - RuleFailureModel pastViolation = newPastViolation("old message", 1, 50, "checksum1"); - - Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(pastViolation)); - assertThat(mapping.get(newViolation), equalTo(pastViolation)); + public void before() { + setupData("shared"); + Snapshot snapshot = getSession().getSingleResult(Snapshot.class, "id", 1000); + ResourcePersister resourcePersister = mock(ResourcePersister.class); + when(resourcePersister.saveResource((Project) anyObject(), eq(javaFile))).thenReturn(snapshot); + when(resourcePersister.getSnapshot(javaFile)).thenReturn(snapshot); + tracker = mock(ViolationTrackingDecorator.class); + decorator = new ViolationPersisterDecorator(tracker, resourcePersister, new DefaultRuleFinder(getSessionFactory()), getSession()); } @Test - public void sameRuleAndLineMessage() { - Violation newViolation = newViolation("message", 1, 50, "checksum1"); - RuleFailureModel pastViolation = newPastViolation("message", 1, 50, "checksum2"); - - Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(pastViolation)); - assertThat(mapping.get(newViolation), equalTo(pastViolation)); + public void shouldSaveViolations() { + Violation violation1a = Violation.create(rule1, javaFile) + .setSeverity(RulePriority.CRITICAL).setLineId(20).setCost(55.6).setMessage("the message") + .setChecksum("checksum").setCreatedAt(DateUtils.parseDate("2010-12-25")); + Violation violation1b = Violation.create(rule1, javaFile) + .setSeverity(RulePriority.CRITICAL).setLineId(50).setCost(80.0); + Violation violation2 = Violation.create(rule2, javaFile) + .setSeverity(RulePriority.MINOR).setSwitchedOff(true); + + decorator.saveViolations(project, Arrays.asList(violation1a, violation1b, violation2)); + + checkTables("shouldSaveViolations", "rule_failures"); } @Test - public void pastMeasureHasNoChecksum() { - Violation newViolation = newViolation("message", 1, 50, null); - RuleFailureModel pastViolation = newPastViolation("message", 1, 51, null); + public void shouldCopyPermanentIdFromReferenceViolation() { + RuleFailureModel referenceViolation = getSession().getSingleResult(RuleFailureModel.class, "id", 1); + Violation violation = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message"); + when(tracker.getReferenceViolation(violation)).thenReturn(referenceViolation); - Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(pastViolation)); - assertThat(mapping.get(newViolation), is(nullValue())); - } - - @Test - public void sameRuleAndMessageAndChecksumButDifferentLine() { - Violation newViolation = newViolation("message", 1, 50, "checksum1"); - RuleFailureModel pastViolation = newPastViolation("message", 2, 50, "checksum1"); + decorator.saveViolations(project, Arrays.asList(violation)); - Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(pastViolation)); - assertThat(mapping.get(newViolation), equalTo(pastViolation)); + checkTables("shouldCopyPermanentIdFromReferenceViolation", "rule_failures"); } - - @Test - public void shouldCreateNewViolationWhenSameRuleSameMessageButDifferentLineAndChecksum() { - Violation newViolation = newViolation("message", 1, 50, "checksum1"); - RuleFailureModel pastViolation = newPastViolation("message", 2, 50, "checksum2"); - - Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(pastViolation)); - assertThat(mapping.get(newViolation), is(nullValue())); - } - - @Test - public void shouldNotTrackViolationIfDifferentRule() { - Violation newViolation = newViolation("message", 1, 50, "checksum1"); - RuleFailureModel pastViolation = newPastViolation("message", 1, 51, "checksum1"); - - Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(pastViolation)); - assertThat(mapping.get(newViolation), is(nullValue())); - } - - @Test - public void shouldCompareViolationsWithDatabaseFormat() { - // violation messages are trimmed and can be abbreviated when persisted in database. - // Comparing violation messages must use the same format. - Violation newViolation = newViolation("message", 1, 50, "checksum1"); - RuleFailureModel pastViolation = newPastViolation(" message ", 1, 50, "checksum2"); - - Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(pastViolation)); - assertThat(mapping.get(newViolation), equalTo(pastViolation)); - } - - private Violation newViolation(String message, int lineId, int ruleId) { - Rule rule = Rule.create().setKey("rule"); - rule.setId(ruleId); - return Violation.create(rule, null).setLineId(lineId).setMessage(message); - } - - private Violation newViolation(String message, int lineId, int ruleId, String lineChecksum) { - Violation violation = newViolation(message, lineId, ruleId); - if (decorator.checksums == null) { - decorator.checksums = Lists.newArrayListWithExpectedSize(100); - } - for (int i = decorator.checksums.size() - 1; i < lineId; i++) { - decorator.checksums.add(""); - } - if (lineChecksum != null) { - decorator.checksums.set(lineId - 1, ViolationPersisterDecorator.getChecksum(lineChecksum)); - } - return violation; - } - - private RuleFailureModel newPastViolation(String message, int lineId, int ruleId) { - RuleFailureModel pastViolation = new RuleFailureModel(); - pastViolation.setId(lineId + ruleId); - pastViolation.setLine(lineId); - pastViolation.setMessage(message); - pastViolation.setRuleId(ruleId); - return pastViolation; - } - - private RuleFailureModel newPastViolation(String message, int lineId, int ruleId, String lineChecksum) { - RuleFailureModel pastViolation = newPastViolation(message, lineId, ruleId); - if (lineChecksum != null) { - pastViolation.setChecksum(ViolationPersisterDecorator.getChecksum(lineChecksum)); - } - return pastViolation; - } - } diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/ViolationTrackingDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/ViolationTrackingDecoratorTest.java new file mode 100644 index 00000000000..848e990ecad --- /dev/null +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/ViolationTrackingDecoratorTest.java @@ -0,0 +1,176 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.timemachine; + +import com.google.common.collect.Lists; +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.database.model.RuleFailureModel; +import org.sonar.api.resources.Project; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.Violation; +import org.sonar.api.utils.DateUtils; + +import java.text.ParseException; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ViolationTrackingDecoratorTest { + + private ViolationTrackingDecorator decorator; + private Date analysisDate = DateUtils.parseDate("2010-12-25"); + + @Before + public void setUp() throws ParseException { + Project project = mock(Project.class); + when(project.getAnalysisDate()).thenReturn(analysisDate); + decorator = new ViolationTrackingDecorator(project, null, null); + } + + @Test + public void checksumShouldHaveGreaterPriorityThanLine() { + RuleFailureModel referenceViolation1 = newReferenceViolation("message", 1, 50, "checksum1"); + RuleFailureModel referenceViolation2 = newReferenceViolation("message", 3, 50, "checksum2"); + + Violation newViolation1 = newViolation("message", 3, 50, "checksum1"); + Violation newViolation2 = newViolation("message", 5, 50, "checksum2"); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation1, newViolation2), + Lists.newArrayList(referenceViolation1, referenceViolation2)); + assertThat(mapping.get(newViolation1), equalTo(referenceViolation1)); + assertThat(mapping.get(newViolation2), equalTo(referenceViolation2)); + } + + @Test + public void sameRuleAndLineAndChecksumButDifferentMessages() { + Violation newViolation = newViolation("new message", 1, 50, "checksum1"); + RuleFailureModel referenceViolation = newReferenceViolation("old message", 1, 50, "checksum1"); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation)); + assertThat(mapping.get(newViolation), equalTo(referenceViolation)); + } + + @Test + public void sameRuleAndLineMessage() { + Violation newViolation = newViolation("message", 1, 50, "checksum1"); + RuleFailureModel refernceViolation = newReferenceViolation("message", 1, 50, "checksum2"); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(refernceViolation)); + assertThat(mapping.get(newViolation), equalTo(refernceViolation)); + } + + @Test + public void shouldIgnoreReferenceMeasureWithoutChecksum() { + Violation newViolation = newViolation("message", 1, 50, null); + RuleFailureModel referenceViolation = newReferenceViolation("message", 1, 51, null); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation)); + assertThat(mapping.get(newViolation), is(nullValue())); + } + + @Test + public void sameRuleAndMessageAndChecksumButDifferentLine() { + Violation newViolation = newViolation("message", 1, 50, "checksum1"); + RuleFailureModel referenceViolation = newReferenceViolation("message", 2, 50, "checksum1"); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation)); + assertThat(mapping.get(newViolation), equalTo(referenceViolation)); + } + + @Test + public void shouldCreateNewViolationWhenSameRuleSameMessageButDifferentLineAndChecksum() { + Violation newViolation = newViolation("message", 1, 50, "checksum1"); + RuleFailureModel referenceViolation = newReferenceViolation("message", 2, 50, "checksum2"); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation)); + assertThat(mapping.get(newViolation), is(nullValue())); + } + + @Test + public void shouldNotTrackViolationIfDifferentRule() { + Violation newViolation = newViolation("message", 1, 50, "checksum1"); + RuleFailureModel referenceViolation = newReferenceViolation("message", 1, 51, "checksum1"); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation)); + assertThat(mapping.get(newViolation), is(nullValue())); + } + + @Test + public void shouldCompareViolationsWithDatabaseFormat() { + // violation messages are trimmed and can be abbreviated when persisted in database. + // Comparing violation messages must use the same format. + Violation newViolation = newViolation("message", 1, 50, "checksum1"); + RuleFailureModel referenceViolation = newReferenceViolation(" message ", 1, 50, "checksum2"); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation)); + assertThat(mapping.get(newViolation), equalTo(referenceViolation)); + } + + @Test + public void shouldSetDateOfNewViolations() { + Violation newViolation = newViolation("message", 1, 50, "checksum"); + assertThat(newViolation.getCreatedAt(), nullValue()); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Collections.<RuleFailureModel>emptyList()); + assertThat(mapping.size(), is(0)); + assertThat(newViolation.getCreatedAt(), is(analysisDate)); + } + + @Test + public void shouldCopyViolationDate() { + Violation newViolation = newViolation("message", 1, 50, "checksum"); + RuleFailureModel referenceViolation = newReferenceViolation("", 1, 50, "checksum"); + Date referenceDate = DateUtils.parseDate("2009-05-18"); + referenceViolation.setCreatedAt(referenceDate); + assertThat(newViolation.getCreatedAt(), nullValue()); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.<RuleFailureModel>newArrayList(referenceViolation)); + assertThat(mapping.size(), is(1)); + assertThat(newViolation.getCreatedAt(), is(referenceDate)); + } + + private Violation newViolation(String message, int lineId, int ruleId) { + Rule rule = Rule.create().setKey("rule"); + rule.setId(ruleId); + return Violation.create(rule, null).setLineId(lineId).setMessage(message); + } + + private Violation newViolation(String message, int lineId, int ruleId, String lineChecksum) { + return newViolation(message, lineId, ruleId).setChecksum(lineChecksum); + } + + private RuleFailureModel newReferenceViolation(String message, int lineId, int ruleId, String lineChecksum) { + RuleFailureModel referenceViolation = new RuleFailureModel(); + referenceViolation.setId(lineId + ruleId); + referenceViolation.setLine(lineId); + referenceViolation.setMessage(message); + referenceViolation.setRuleId(ruleId); + referenceViolation.setChecksum(lineChecksum); + return referenceViolation; + } + +} diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shared.xml b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest/shared.xml index 90a3f202297..90a3f202297 100644 --- a/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shared.xml +++ b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest/shared.xml diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldCopyPermanentIdFromPastViolation-result.xml b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest/shouldCopyPermanentIdFromReferenceViolation-result.xml index 881a88dc3bb..fc52aa2bd62 100644 --- a/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldCopyPermanentIdFromPastViolation-result.xml +++ b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest/shouldCopyPermanentIdFromReferenceViolation-result.xml @@ -22,5 +22,5 @@ <rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> <rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> - <rule_failures switched_off="false" permanent_id="1" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="line_checksum"/> + <rule_failures switched_off="false" permanent_id="1" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="[null]" checksum="[null]"/> </dataset> diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldInsertViolations-result.xml b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest/shouldSaveViolations-result.xml index 3b3215ffe11..726b925bf12 100644 --- a/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldInsertViolations-result.xml +++ b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest/shouldSaveViolations-result.xml @@ -20,7 +20,7 @@ <rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> <rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> - <rule_failures switched_off="false" permanent_id="3" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="the message" LINE="20" COST="55.6" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> - <rule_failures switched_off="false" permanent_id="4" ID="4" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="[null]" LINE="50" COST="80" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> - <rule_failures switched_off="false" permanent_id="5" ID="5" SNAPSHOT_ID="1000" RULE_ID="31" FAILURE_LEVEL="1" MESSAGE="[null]" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> + <rule_failures switched_off="false" permanent_id="3" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="the message" LINE="20" COST="55.6" created_at="2010-12-25 00:00:00.00" checksum="checksum"/> + <rule_failures switched_off="false" permanent_id="4" ID="4" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="[null]" LINE="50" COST="80" created_at="[null]" checksum="[null]"/> + <rule_failures switched_off="true" permanent_id="5" ID="5" SNAPSHOT_ID="1000" RULE_ID="31" FAILURE_LEVEL="1" MESSAGE="[null]" LINE="[null]" COST="[null]" created_at="[null]" checksum="[null]"/> </dataset>
\ No newline at end of file diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java index eb6c4552073..08931556821 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java @@ -60,7 +60,6 @@ public class BatchModule extends Module { addComponent(MemoryOptimizer.class); addComponent(DefaultResourcePersister.class); addComponent(SourcePersister.class); - addComponent(ViolationPersister.class); } addComponent(Plugins.class); diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java index d603c34a1df..59d3dff04f9 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java @@ -31,7 +31,6 @@ import org.sonar.api.resources.ProjectFileSystem; import org.sonar.api.rules.DefaultRulesManager; import org.sonar.api.utils.SonarException; import org.sonar.batch.*; -import org.sonar.batch.components.PastViolationsLoader; import org.sonar.batch.components.TimeMachineConfiguration; import org.sonar.batch.events.EventBus; import org.sonar.batch.index.DefaultIndex; @@ -80,7 +79,6 @@ public class ProjectModule extends Module { // the Snapshot component will be removed when asynchronous measures are improved (required for AsynchronousMeasureSensor) addComponent(getComponent(DefaultResourcePersister.class).getSnapshot(project)); addComponent(TimeMachineConfiguration.class); - addComponent(PastViolationsLoader.class); } addComponent(org.sonar.api.database.daos.MeasuresDao.class); addComponent(ProfilesDao.class); diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/PastViolationsLoader.java b/sonar-batch/src/main/java/org/sonar/batch/components/PastViolationsLoader.java deleted file mode 100644 index 6168ebca199..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/components/PastViolationsLoader.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2011 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * Sonar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.components; - -import org.sonar.api.BatchExtension; -import org.sonar.api.database.DatabaseSession; -import org.sonar.api.database.model.RuleFailureModel; -import org.sonar.api.database.model.Snapshot; -import org.sonar.api.database.model.SnapshotSource; -import org.sonar.api.resources.Resource; -import org.sonar.api.utils.SonarException; -import org.sonar.batch.index.ResourcePersister; -import org.sonar.core.NotDryRun; - -import java.util.Collections; -import java.util.List; - -@NotDryRun -public class PastViolationsLoader implements BatchExtension { - - private DatabaseSession session; - private ResourcePersister resourcePersister; - - public PastViolationsLoader(DatabaseSession session, ResourcePersister resourcePersister) { - this.session = session; - this.resourcePersister = resourcePersister; - } - - public List<RuleFailureModel> getPastViolations(Resource resource) { - if (resource == null) { - return Collections.emptyList(); - } - - Snapshot snapshot = resourcePersister.getSnapshot(resource); - if (snapshot == null) { - throw new SonarException("This resource has no snapshot ???" + resource); - } - Snapshot previousLastSnapshot = resourcePersister.getLastSnapshot(snapshot, true); - if (previousLastSnapshot == null) { - return Collections.emptyList(); - } - return session.getResults(RuleFailureModel.class, - "snapshotId", previousLastSnapshot.getId()); - } - - public SnapshotSource getSource(Resource resource) { - Snapshot snapshot = resourcePersister.getSnapshot(resource); - return session.getSingleResult(SnapshotSource.class, - "snapshotId", snapshot.getId()); - } - -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java index 1accc7b4ea6..5aeac943af9 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java @@ -408,6 +408,10 @@ public class DefaultIndex extends SonarIndex { } } + public String getSource(Resource resource) { + return persistence.getSource(resource); + } + /** * Does nothing if the resource is already registered. */ diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java index f5722b7f5a2..35baf93c09d 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java @@ -78,6 +78,10 @@ public final class DefaultPersistenceManager implements PersistenceManager { sourcePersister.saveSource(file, source); } + public String getSource(Resource resource) { + return sourcePersister.getSource(resource); + } + public void saveMeasure(Resource resource, Measure measure) { if (ResourceUtils.isPersistable(resource)) { measurePersister.saveMeasure(resource, measure); diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java b/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java index 98de69eb77f..2203c2e4768 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java @@ -42,6 +42,8 @@ public interface PersistenceManager { void setSource(Resource file, String source); + String getSource(Resource resource); + void saveMeasure(Resource resource, Measure measure); Measure reloadMeasure(Measure measure); diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/ReadOnlyPersistenceManager.java b/sonar-batch/src/main/java/org/sonar/batch/index/ReadOnlyPersistenceManager.java index 7682a3dbb6e..1470031672c 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/ReadOnlyPersistenceManager.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/ReadOnlyPersistenceManager.java @@ -19,6 +19,7 @@ */ package org.sonar.batch.index; +import com.google.common.collect.Maps; import org.sonar.api.batch.Event; import org.sonar.api.database.model.Snapshot; import org.sonar.api.design.Dependency; @@ -29,10 +30,14 @@ import org.sonar.api.resources.Resource; import java.util.Collections; import java.util.List; +import java.util.Map; public final class ReadOnlyPersistenceManager implements PersistenceManager { + private Map<Resource, String> sources = Maps.newHashMap(); + public void clear() { + sources.clear(); } public void setDelayedMode(boolean b) { @@ -49,6 +54,11 @@ public final class ReadOnlyPersistenceManager implements PersistenceManager { } public void setSource(Resource file, String source) { + sources.put(file, source); + } + + public String getSource(Resource resource) { + return sources.get(resource); } public void saveMeasure(Resource resource, Measure measure) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java index 0e8f700237c..d4fdd10300c 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java @@ -49,6 +49,15 @@ public final class SourcePersister { addToCache(snapshot); } + public String getSource(Resource resource) { + SnapshotSource source = null; + Snapshot snapshot = resourcePersister.getSnapshot(resource); + if (snapshot!=null && snapshot.getId()!=null) { + source = session.getSingleResult(SnapshotSource.class, "snapshotId", snapshot.getId()); + } + return source!=null ? source.getData() : null; + } + private boolean isCached(Snapshot snapshot) { return savedSnapshotIds.contains(snapshot.getId()); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/ViolationPersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/ViolationPersister.java deleted file mode 100644 index 0b15823d5c7..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/index/ViolationPersister.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2011 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * Sonar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.index; - -import org.sonar.api.database.DatabaseSession; -import org.sonar.api.database.model.RuleFailureModel; -import org.sonar.api.database.model.Snapshot; -import org.sonar.api.resources.Project; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.RuleFinder; -import org.sonar.api.rules.Violation; - -public final class ViolationPersister { - - private DatabaseSession session; - private ResourcePersister resourcePersister; - private RuleFinder ruleFinder; - - public ViolationPersister(DatabaseSession session, ResourcePersister resourcePersister, RuleFinder ruleFinder) { - this.session = session; - this.resourcePersister = resourcePersister; - this.ruleFinder = ruleFinder; - } - - void saveViolation(Project project, Violation violation) { - saveViolation(project, violation, null, null); - } - - public void saveViolation(Project project, Violation violation, RuleFailureModel pastViolation, String checksum) { - Snapshot snapshot = resourcePersister.saveResource(project, violation.getResource()); - - RuleFailureModel model = createModel(violation); - if (pastViolation!=null) { - model.setCreatedAt(pastViolation.getCreatedAt()); - model.setPermanentId(pastViolation.getPermanentId()); - model.setSwitchedOff(pastViolation.isSwitchedOff()); - } else { - // avoid plugins setting date - model.setCreatedAt(snapshot.getCreatedAt()); - } - model.setSnapshotId(snapshot.getId()); - model.setChecksum(checksum); - session.saveWithoutFlush(model); - - if (model.getPermanentId()==null) { - model.setPermanentId(model.getId()); - session.saveWithoutFlush(model); - } - - // the following fields can have been changed - violation.setMessage(model.getMessage());// the message can be changed in the class RuleFailure (truncate + trim) - violation.setCreatedAt(model.getCreatedAt()); - violation.setSwitchedOff(model.isSwitchedOff()); - } - - public void commit() { - session.commit(); - } - - private RuleFailureModel createModel(Violation violation) { - RuleFailureModel model = new RuleFailureModel(); - Rule rule = ruleFinder.findByKey(violation.getRule().getRepositoryKey(), violation.getRule().getKey()); - model.setRuleId(rule.getId()); - model.setPriority(violation.getSeverity()); - model.setLine(violation.getLineId()); - model.setMessage(violation.getMessage()); - model.setCost(violation.getCost()); - return model; - } - -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/components/PastViolationsLoaderTest.java b/sonar-batch/src/test/java/org/sonar/batch/components/PastViolationsLoaderTest.java deleted file mode 100644 index 965f4f8d85f..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/components/PastViolationsLoaderTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2011 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * Sonar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.components; - -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.database.model.RuleFailureModel; -import org.sonar.api.database.model.Snapshot; -import org.sonar.api.resources.JavaFile; -import org.sonar.api.resources.Resource; -import org.sonar.batch.index.ResourcePersister; -import org.sonar.jpa.test.AbstractDbUnitTestCase; - -import java.util.List; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.notNullValue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; - -public class PastViolationsLoaderTest extends AbstractDbUnitTestCase { - - private ResourcePersister resourcePersister; - private PastViolationsLoader loader; - - @Before - public void setUp() { - setupData("shared"); - resourcePersister = mock(ResourcePersister.class); - loader = new PastViolationsLoader(getSession(), resourcePersister); - } - - @Test - public void shouldGetPastResourceViolations() { - Snapshot snapshot = getSession().getSingleResult(Snapshot.class, "id", 1000); - doReturn(snapshot).when(resourcePersister) - .getSnapshot(any(Resource.class)); - doReturn(snapshot).when(resourcePersister) - .getLastSnapshot(any(Snapshot.class), anyBoolean()); - - List<RuleFailureModel> violations = loader.getPastViolations(new JavaFile("file")); - - assertThat(violations.size(), is(2)); - } - - @Test - public void shouldReturnEmptyList() { - List<RuleFailureModel> violations = loader.getPastViolations(null); - - assertThat(violations, notNullValue()); - assertThat(violations.size(), is(0)); - } - -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/ViolationPersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/ViolationPersisterTest.java deleted file mode 100644 index bb5bc1a34e9..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/index/ViolationPersisterTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2011 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * Sonar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.index; - -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.database.model.RuleFailureModel; -import org.sonar.api.database.model.Snapshot; -import org.sonar.api.resources.JavaFile; -import org.sonar.api.resources.Project; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.RulePriority; -import org.sonar.api.rules.Violation; -import org.sonar.core.components.DefaultRuleFinder; -import org.sonar.jpa.test.AbstractDbUnitTestCase; - -import static org.mockito.Matchers.anyObject; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class ViolationPersisterTest extends AbstractDbUnitTestCase { - - private ViolationPersister violationPersister; - private Rule rule1 = Rule.create("checkstyle", "com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck", "Check Header"); - private Rule rule2 = Rule.create("checkstyle", "com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck", "Equals Avoid Null"); - private JavaFile javaFile = new JavaFile("org.foo.Bar"); - Project project = new Project("project"); - - @Before - public void before() { - setupData("shared"); - Snapshot snapshot = getSession().getSingleResult(Snapshot.class, "id", 1000); - ResourcePersister resourcePersister = mock(ResourcePersister.class); - when(resourcePersister.saveResource((Project) anyObject(), eq(javaFile))).thenReturn(snapshot); - when(resourcePersister.getSnapshot(javaFile)).thenReturn(snapshot); - violationPersister = new ViolationPersister(getSession(), resourcePersister, new DefaultRuleFinder(getSessionFactory())); - } - - @Test - public void shouldSaveViolations() { - Violation violation1a = Violation.create(rule1, javaFile) - .setSeverity(RulePriority.CRITICAL).setLineId(20).setCost(55.6) - .setMessage("the message"); - Violation violation1b = Violation.create(rule1, javaFile) - .setSeverity(RulePriority.CRITICAL).setLineId(50).setCost(80.0); - Violation violation2 = Violation.create(rule2, javaFile) - .setSeverity(RulePriority.MINOR); - - violationPersister.saveViolation(project, violation1a); - violationPersister.saveViolation(project, violation1b); - violationPersister.saveViolation(project, violation2); - - checkTables("shouldInsertViolations", "rule_failures"); - } - - @Test - public void shouldCopyPermanentIdFromPastViolation() { - RuleFailureModel pastViolation = getSession().getSingleResult(RuleFailureModel.class, "id", 1); - - Violation violation = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message"); - violationPersister.saveViolation(project, violation, pastViolation, "line_checksum"); - - checkTables("shouldCopyPermanentIdFromPastViolation", "rule_failures"); - } - - @Test - public void shouldCopySwitchedOffFromPastViolation() { - RuleFailureModel pastViolation1 = getSession().getSingleResult(RuleFailureModel.class, "id", 1); - Violation violation1 = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message"); - violationPersister.saveViolation(project, violation1, pastViolation1, "line_checksum"); - - RuleFailureModel pastViolation2 = getSession().getSingleResult(RuleFailureModel.class, "id", 2); - Violation violation2 = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message"); - violationPersister.saveViolation(project, violation2, pastViolation2, "line_checksum"); - - checkTables("shouldCopySwitchedOffFromPastViolation", "rule_failures"); - } -} diff --git a/sonar-batch/src/test/resources/org/sonar/batch/components/PastViolationsLoaderTest/shared.xml b/sonar-batch/src/test/resources/org/sonar/batch/components/PastViolationsLoaderTest/shared.xml deleted file mode 100644 index 9e11773eca9..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/components/PastViolationsLoaderTest/shared.xml +++ /dev/null @@ -1,24 +0,0 @@ -<dataset> - - <rules_categories id="1" name="Efficiency" description="[null]"/> - <rules_categories id="6" name="Usability" description="[null]"/> - - <rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" - plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" - cardinality="SINGLE" parent_id="[null]"/> - - <rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck" - plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" - cardinality="SINGLE" parent_id="[null]"/> - - <projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]" - name="Bar" long_name="org.foo.Bar" description="[null]" - enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/> - - <snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]" - scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path="" - status="U" islast="false" depth="3" /> - - <rule_failures switched_off="[null]" permanent_id="[null]" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" /> - <rule_failures switched_off="[null]" permanent_id="[null]" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" /> -</dataset> diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldCopySwitchedOffFromPastViolation-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldCopySwitchedOffFromPastViolation-result.xml deleted file mode 100644 index bc366b16a45..00000000000 --- a/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldCopySwitchedOffFromPastViolation-result.xml +++ /dev/null @@ -1,27 +0,0 @@ -<dataset> - - <rules_categories id="1" name="Efficiency" description="[null]"/> - <rules_categories id="6" name="Usability" description="[null]"/> - - <rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" - plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" - cardinality="SINGLE" parent_id="[null]"/> - - <rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck" - plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" - cardinality="SINGLE" parent_id="[null]"/> - - <projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]" - name="Bar" long_name="org.foo.Bar" description="[null]" - enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/> - - <snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]" - scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path="" - status="U" islast="false" depth="3" /> - - <rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> - <rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> - - <rule_failures switched_off="false" permanent_id="1" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="line_checksum"/> - <rule_failures switched_off="true" permanent_id="2" ID="4" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="line_checksum"/> -</dataset> diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java index 4c82198ffdd..1e17e75dad1 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java @@ -99,6 +99,11 @@ public abstract class SonarIndex implements DirectedGraphAccessor<Resource, Depe */ public abstract void setSource(Resource reference, String source) throws DuplicatedSourceException; + /** + * @since 2.9 + */ + public abstract String getSource(Resource resource); + public abstract Project getProject(); public final Collection<Resource> getResources() { @@ -133,8 +138,6 @@ public abstract class SonarIndex implements DirectedGraphAccessor<Resource, Depe * as a parameter. * * @since 2.7 - * @param the - * resource on which violations are searched * @return the list of violations */ public final List<Violation> getViolations(Resource resource) { @@ -153,8 +156,6 @@ public abstract class SonarIndex implements DirectedGraphAccessor<Resource, Depe /** * Warning: the resource is automatically indexed for backward-compatibility, but it should be explictly * indexed before. Next versions will deactivate this automatic indexation. - * - * @throws SonarException if the metric is unknown. */ public abstract Measure addMeasure(Resource resource, Measure measure); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java b/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java index fc7ec235484..efab4077464 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java @@ -40,6 +40,7 @@ public class Violation { private Double cost; private Date createdAt; private boolean switchedOff=false; + private String checksum; /** * Creates of a violation from a rule. Will need to define the resource later on @@ -238,27 +239,24 @@ public class Violation { * Tells whether this violation is ON or OFF. * * @since 2.8 - * @return true if the violation has been switched off */ public boolean isSwitchedOff() { return switchedOff; } - @Override - public boolean equals(Object obj) { - if (!(obj instanceof Violation)) { - return false; - } - if (this == obj) { - return true; - } - Violation other = (Violation) obj; - return new EqualsBuilder().append(rule, other.getRule()).append(resource, other.getResource()).isEquals(); + /** + * Checksum is available in decorators executed after the barrier {@link org.sonar.api.batch.DecoratorBarriers#END_OF_VIOLATION_TRACKING} + */ + public String getChecksum() { + return checksum; } - @Override - public int hashCode() { - return new HashCodeBuilder(17, 37).append(getRule()).append(getResource()).toHashCode(); + /** + * For internal use only. Checksum is automatically set by Sonar. Plugins must not call this method. + */ + public Violation setChecksum(String s) { + this.checksum = s; + return this; } @Override |