3 * Copyright (C) 2009-2017 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.computation.task.projectanalysis.issue;
22 import com.google.common.collect.ImmutableMap;
23 import java.util.Date;
24 import org.junit.Test;
25 import org.sonar.api.utils.Duration;
26 import org.sonar.core.issue.DefaultIssue;
27 import org.sonar.core.issue.IssueChangeContext;
28 import org.sonar.db.protobuf.DbCommons;
29 import org.sonar.db.protobuf.DbIssues;
30 import org.sonar.server.issue.IssueFieldsSetter;
31 import org.sonar.server.issue.workflow.IssueWorkflow;
33 import static com.google.common.collect.Lists.newArrayList;
34 import static org.assertj.core.api.Assertions.assertThat;
35 import static org.mockito.Mockito.mock;
36 import static org.mockito.Mockito.never;
37 import static org.mockito.Mockito.verify;
38 import static org.mockito.Mockito.when;
39 import static org.sonar.api.issue.Issue.RESOLUTION_FIXED;
40 import static org.sonar.api.issue.Issue.STATUS_CLOSED;
41 import static org.sonar.api.issue.Issue.STATUS_OPEN;
42 import static org.sonar.api.rule.Severity.BLOCKER;
43 import static org.sonar.api.utils.DateUtils.parseDate;
45 public class IssueLifecycleTest {
47 static final Date DEFAULT_DATE = new Date();
49 static final Duration DEFAULT_DURATION = Duration.create(10);
51 IssueChangeContext issueChangeContext = IssueChangeContext.createUser(DEFAULT_DATE, "julien");
53 IssueWorkflow workflow = mock(IssueWorkflow.class);
55 IssueFieldsSetter updater = mock(IssueFieldsSetter.class);
57 DebtCalculator debtCalculator = mock(DebtCalculator.class);
59 IssueLifecycle underTest = new IssueLifecycle(issueChangeContext, workflow, updater, debtCalculator);
62 public void initNewOpenIssue() throws Exception {
63 DefaultIssue issue = new DefaultIssue();
64 when(debtCalculator.calculate(issue)).thenReturn(DEFAULT_DURATION);
66 underTest.initNewOpenIssue(issue);
68 assertThat(issue.key()).isNotNull();
69 assertThat(issue.creationDate()).isNotNull();
70 assertThat(issue.updateDate()).isNotNull();
71 assertThat(issue.status()).isEqualTo(STATUS_OPEN);
72 assertThat(issue.debt()).isEqualTo(DEFAULT_DURATION);
76 public void doAutomaticTransition() throws Exception {
77 DefaultIssue issue = new DefaultIssue();
79 underTest.doAutomaticTransition(issue);
81 verify(workflow).doAutomaticTransition(issue, issueChangeContext);
85 public void mergeExistingOpenIssue() throws Exception {
86 DefaultIssue raw = new DefaultIssue()
89 .setCreationDate(parseDate("2015-10-01"))
90 .setUpdateDate(parseDate("2015-10-02"))
91 .setCloseDate(parseDate("2015-10-03"));
93 DbIssues.Locations issueLocations = DbIssues.Locations.newBuilder()
94 .setTextRange(DbCommons.TextRange.newBuilder()
99 DefaultIssue base = new DefaultIssue()
101 .setCreationDate(parseDate("2015-01-01"))
102 .setUpdateDate(parseDate("2015-01-02"))
103 .setCloseDate(parseDate("2015-01-03"))
104 .setResolution(RESOLUTION_FIXED)
105 .setStatus(STATUS_CLOSED)
106 .setSeverity(BLOCKER)
107 .setAssignee("base assignee")
108 .setAuthorLogin("base author")
109 .setTags(newArrayList("base tag"))
110 .setOnDisabledRule(true)
111 .setSelectedAt(1000L)
113 .setMessage("message")
115 .setEffort(Duration.create(15L))
116 .setManualSeverity(false)
117 .setLocations(issueLocations);
119 when(debtCalculator.calculate(raw)).thenReturn(DEFAULT_DURATION);
121 underTest.mergeExistingOpenIssue(raw, base);
123 assertThat(raw.isNew()).isFalse();
124 assertThat(raw.key()).isEqualTo("BASE_KEY");
125 assertThat(raw.creationDate()).isEqualTo(base.creationDate());
126 assertThat(raw.updateDate()).isEqualTo(base.updateDate());
127 assertThat(raw.closeDate()).isEqualTo(base.closeDate());
128 assertThat(raw.resolution()).isEqualTo(RESOLUTION_FIXED);
129 assertThat(raw.status()).isEqualTo(STATUS_CLOSED);
130 assertThat(raw.assignee()).isEqualTo("base assignee");
131 assertThat(raw.authorLogin()).isEqualTo("base author");
132 assertThat(raw.tags()).containsOnly("base tag");
133 assertThat(raw.debt()).isEqualTo(DEFAULT_DURATION);
134 assertThat(raw.isOnDisabledRule()).isTrue();
135 assertThat(raw.selectedAt()).isEqualTo(1000L);
137 verify(updater).setPastSeverity(raw, BLOCKER, issueChangeContext);
138 verify(updater).setPastLine(raw, 10);
139 verify(updater).setPastMessage(raw, "message", issueChangeContext);
140 verify(updater).setPastEffort(raw, Duration.create(15L), issueChangeContext);
141 verify(updater).setPastLocations(raw, issueLocations);
145 public void mergeExistingOpenIssue_with_manual_severity() throws Exception {
146 DefaultIssue raw = new DefaultIssue()
149 DefaultIssue base = new DefaultIssue()
151 .setResolution(RESOLUTION_FIXED)
152 .setStatus(STATUS_CLOSED)
153 .setSeverity(BLOCKER)
154 .setManualSeverity(true);
156 underTest.mergeExistingOpenIssue(raw, base);
158 assertThat(raw.manualSeverity()).isTrue();
159 assertThat(raw.severity()).isEqualTo(BLOCKER);
161 verify(updater, never()).setPastSeverity(raw, BLOCKER, issueChangeContext);
165 public void mergeExistingOpenIssue_with_attributes() throws Exception {
166 DefaultIssue raw = new DefaultIssue()
169 DefaultIssue base = new DefaultIssue()
171 .setResolution(RESOLUTION_FIXED)
172 .setStatus(STATUS_CLOSED)
173 .setSeverity(BLOCKER)
174 .setAttributes(ImmutableMap.of("JIRA", "SONAR-01"));
176 underTest.mergeExistingOpenIssue(raw, base);
178 assertThat(raw.attributes()).containsEntry("JIRA", "SONAR-01");