diff options
Diffstat (limited to 'server/sonar-server')
2 files changed, 190 insertions, 4 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueLifecycle.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueLifecycle.java index 30b4ccac84b..93cbffd32cd 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueLifecycle.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueLifecycle.java @@ -19,13 +19,14 @@ */ package org.sonar.server.computation.issue; +import com.google.common.annotations.VisibleForTesting; import javax.annotation.Nullable; import org.sonar.api.issue.Issue; -import org.sonar.core.util.Uuids; import org.sonar.core.issue.DefaultIssue; import org.sonar.core.issue.IssueChangeContext; import org.sonar.core.issue.IssueUpdater; import org.sonar.core.issue.workflow.IssueWorkflow; +import org.sonar.core.util.Uuids; import org.sonar.server.computation.analysis.AnalysisMetadataHolder; /** @@ -44,10 +45,15 @@ public class IssueLifecycle { private final DebtCalculator debtCalculator; public IssueLifecycle(AnalysisMetadataHolder analysisMetadataHolder, IssueWorkflow workflow, IssueUpdater updater, DebtCalculator debtCalculator) { + this(IssueChangeContext.createScan(analysisMetadataHolder.getAnalysisDate()), workflow, updater, debtCalculator); + } + + @VisibleForTesting + IssueLifecycle(IssueChangeContext changeContext, IssueWorkflow workflow, IssueUpdater updater, DebtCalculator debtCalculator) { this.workflow = workflow; this.updater = updater; this.debtCalculator = debtCalculator; - this.changeContext = IssueChangeContext.createScan(analysisMetadataHolder.getAnalysisDate()); + this.changeContext = changeContext; } public void initNewOpenIssue(DefaultIssue issue) { @@ -70,6 +76,7 @@ public class IssueLifecycle { raw.setAssignee(base.assignee()); raw.setAuthorLogin(base.authorLogin()); raw.setTags(base.tags()); + raw.setAttributes(base.attributes()); raw.setDebt(debtCalculator.calculate(raw)); raw.setOnDisabledRule(base.isOnDisabledRule()); if (base.manualSeverity()) { @@ -79,8 +86,6 @@ public class IssueLifecycle { updater.setPastSeverity(raw, base.severity(), changeContext); } - // TODO attributes - // fields coming from raw updater.setPastLine(raw, base.getLine()); updater.setPastMessage(raw, base.getMessage(), changeContext); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/IssueLifecycleTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/IssueLifecycleTest.java new file mode 100644 index 00000000000..80fbd779a46 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/IssueLifecycleTest.java @@ -0,0 +1,181 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.computation.issue; + +import com.google.common.collect.ImmutableMap; +import java.util.Date; +import org.junit.Test; +import org.sonar.api.utils.Duration; +import org.sonar.core.issue.DefaultIssue; +import org.sonar.core.issue.IssueChangeContext; +import org.sonar.core.issue.IssueUpdater; +import org.sonar.core.issue.workflow.IssueWorkflow; + +import static com.google.common.collect.Lists.newArrayList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.sonar.api.issue.Issue.RESOLUTION_FIXED; +import static org.sonar.api.issue.Issue.STATUS_CLOSED; +import static org.sonar.api.issue.Issue.STATUS_OPEN; +import static org.sonar.api.rule.Severity.BLOCKER; +import static org.sonar.api.utils.DateUtils.parseDate; + +public class IssueLifecycleTest { + + static final Date DEFAULT_DATE = new Date(); + + static final Duration DEFAULT_DURATION = Duration.create(10); + + IssueChangeContext issueChangeContext = IssueChangeContext.createUser(DEFAULT_DATE, "julien"); + + IssueWorkflow workflow = mock(IssueWorkflow.class); + + IssueUpdater updater = mock(IssueUpdater.class); + + DebtCalculator debtCalculator = mock(DebtCalculator.class); + + IssueLifecycle underTest = new IssueLifecycle(issueChangeContext, workflow, updater, debtCalculator); + + @Test + public void initNewOpenIssue() throws Exception { + DefaultIssue issue = new DefaultIssue(); + when(debtCalculator.calculate(issue)).thenReturn(DEFAULT_DURATION); + + underTest.initNewOpenIssue(issue); + + assertThat(issue.key()).isNotNull(); + assertThat(issue.creationDate()).isNotNull(); + assertThat(issue.updateDate()).isNotNull(); + assertThat(issue.status()).isEqualTo(STATUS_OPEN); + assertThat(issue.debt()).isEqualTo(DEFAULT_DURATION); + } + + @Test + public void moveOpenManualIssue() throws Exception { + DefaultIssue issue = new DefaultIssue(); + + underTest.moveOpenManualIssue(issue, 1); + + verify(updater).setLine(issue, 1); + } + + @Test + public void doAutomaticTransition() throws Exception { + DefaultIssue issue = new DefaultIssue(); + + underTest.doAutomaticTransition(issue); + + verify(workflow).doAutomaticTransition(issue, issueChangeContext); + } + + @Test + public void mergeExistingOpenIssue() throws Exception { + DefaultIssue raw = new DefaultIssue() + .setNew(true) + .setKey("RAW_KEY") + .setCreationDate(parseDate("2015-10-01")) + .setUpdateDate(parseDate("2015-10-02")) + .setCloseDate(parseDate("2015-10-03")); + DefaultIssue base = new DefaultIssue() + .setKey("BASE_KEY") + .setCreationDate(parseDate("2015-01-01")) + .setUpdateDate(parseDate("2015-01-02")) + .setCloseDate(parseDate("2015-01-03")) + .setActionPlanKey("BASE_ACTION_PLAN_KEY") + .setResolution(RESOLUTION_FIXED) + .setStatus(STATUS_CLOSED) + .setSeverity(BLOCKER) + .setAssignee("base assignee") + .setAuthorLogin("base author") + .setTags(newArrayList("base tag")) + .setOnDisabledRule(true) + .setSelectedAt(1000L) + .setLine(10) + .setMessage("message") + .setEffortToFix(15d) + .setDebt(Duration.create(15L)) + .setManualSeverity(false); + + when(debtCalculator.calculate(raw)).thenReturn(DEFAULT_DURATION); + + underTest.mergeExistingOpenIssue(raw, base); + + assertThat(raw.isNew()).isFalse(); + assertThat(raw.key()).isEqualTo("BASE_KEY"); + assertThat(raw.creationDate()).isEqualTo(base.creationDate()); + assertThat(raw.updateDate()).isEqualTo(base.updateDate()); + assertThat(raw.closeDate()).isEqualTo(base.closeDate()); + assertThat(raw.actionPlanKey()).isEqualTo("BASE_ACTION_PLAN_KEY"); + assertThat(raw.resolution()).isEqualTo(RESOLUTION_FIXED); + assertThat(raw.status()).isEqualTo(STATUS_CLOSED); + assertThat(raw.assignee()).isEqualTo("base assignee"); + assertThat(raw.authorLogin()).isEqualTo("base author"); + assertThat(raw.tags()).containsOnly("base tag"); + assertThat(raw.debt()).isEqualTo(DEFAULT_DURATION); + assertThat(raw.isOnDisabledRule()).isTrue(); + assertThat(raw.selectedAt()).isEqualTo(1000L); + + verify(updater).setPastSeverity(raw, BLOCKER, issueChangeContext); + verify(updater).setPastLine(raw, 10); + verify(updater).setPastMessage(raw, "message", issueChangeContext); + verify(updater).setPastTechnicalDebt(raw, Duration.create(15L), issueChangeContext); + } + + @Test + public void mergeExistingOpenIssue_with_manual_severity() throws Exception { + DefaultIssue raw = new DefaultIssue() + .setNew(true) + .setKey("RAW_KEY"); + DefaultIssue base = new DefaultIssue() + .setKey("BASE_KEY") + .setResolution(RESOLUTION_FIXED) + .setStatus(STATUS_CLOSED) + .setSeverity(BLOCKER) + .setManualSeverity(true); + + underTest.mergeExistingOpenIssue(raw, base); + + assertThat(raw.manualSeverity()).isTrue(); + assertThat(raw.severity()).isEqualTo(BLOCKER); + + verify(updater, never()).setPastSeverity(raw, BLOCKER, issueChangeContext); + } + + @Test + public void mergeExistingOpenIssue_with_attributes() throws Exception { + DefaultIssue raw = new DefaultIssue() + .setNew(true) + .setKey("RAW_KEY"); + DefaultIssue base = new DefaultIssue() + .setKey("BASE_KEY") + .setResolution(RESOLUTION_FIXED) + .setStatus(STATUS_CLOSED) + .setSeverity(BLOCKER) + .setAttributes(ImmutableMap.of("JIRA", "SONAR-01")); + + underTest.mergeExistingOpenIssue(raw, base); + + assertThat(raw.attributes()).containsEntry("JIRA", "SONAR-01"); + } +} |