]> source.dussan.org Git - sonarqube.git/blob
cf185e9ed753c364c2a7bbde6e1713c7e5ff09c9
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2022 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20 package org.sonar.server.issue.ws;
21
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Date;
25 import java.util.List;
26 import java.util.Set;
27 import org.junit.Before;
28 import org.junit.Test;
29 import org.junit.runner.RunWith;
30 import org.mockito.Mock;
31 import org.mockito.junit.MockitoJUnitRunner;
32 import org.sonar.api.resources.Languages;
33 import org.sonar.api.utils.Duration;
34 import org.sonar.api.utils.Durations;
35 import org.sonar.db.component.ComponentDto;
36 import org.sonar.db.issue.IssueChangeDto;
37 import org.sonar.db.issue.IssueDto;
38 import org.sonar.db.rule.RuleDto;
39 import org.sonar.db.user.UserDto;
40 import org.sonar.server.issue.TextRangeResponseFormatter;
41 import org.sonar.server.issue.workflow.Transition;
42 import org.sonarqube.ws.Common;
43 import org.sonarqube.ws.Issues.Issue;
44 import org.sonarqube.ws.Issues.Operation;
45
46 import static java.lang.System.currentTimeMillis;
47 import static java.util.stream.Collectors.toList;
48 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
49 import static org.assertj.core.api.Assertions.assertThat;
50 import static org.mockito.ArgumentMatchers.any;
51 import static org.mockito.ArgumentMatchers.eq;
52 import static org.mockito.Mockito.when;
53 import static org.sonar.api.resources.Qualifiers.UNIT_TEST_FILE;
54 import static org.sonar.api.rule.RuleKey.EXTERNAL_RULE_REPO_PREFIX;
55 import static org.sonar.api.rules.RuleType.CODE_SMELL;
56 import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT;
57 import static org.sonar.api.utils.DateUtils.formatDateTime;
58 import static org.sonar.db.component.ComponentDto.BRANCH_KEY_SEPARATOR;
59 import static org.sonar.db.component.ComponentDto.PULL_REQUEST_SEPARATOR;
60 import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
61 import static org.sonar.db.issue.IssueTesting.newIssue;
62 import static org.sonar.db.issue.IssueTesting.newIssuechangeDto;
63 import static org.sonar.db.rule.RuleTesting.newRule;
64 import static org.sonar.db.user.UserTesting.newUserDto;
65 import static org.sonar.server.issue.index.IssueScope.MAIN;
66 import static org.sonar.server.issue.index.IssueScope.TEST;
67
68 @RunWith(MockitoJUnitRunner.class)
69 public class SearchResponseFormatFormatOperationTest {
70
71   private SearchResponseFormat searchResponseFormat;
72
73   private final Durations durations = new Durations();
74   @Mock
75   private Languages languages;
76   @Mock
77   private TextRangeResponseFormatter textRangeResponseFormatter;
78   @Mock
79   private UserResponseFormatter userResponseFormatter;
80   @Mock
81   private Common.User user;
82
83   private SearchResponseData searchResponseData;
84   private IssueDto issueDto;
85   private ComponentDto componentDto;
86   private UserDto userDto;
87
88
89   @Before
90   public void setUp() {
91     searchResponseFormat = new SearchResponseFormat(durations, languages, textRangeResponseFormatter, userResponseFormatter);
92     searchResponseData = newSearchResponseData();
93     issueDto = searchResponseData.getIssues().get(0);
94     componentDto = searchResponseData.getComponents().iterator().next();
95     userDto = searchResponseData.getUsers().get(0);
96     when(userResponseFormatter.formatUser(any(Common.User.Builder.class), eq(userDto))).thenReturn(user);
97   }
98
99   @Test
100   public void formatOperation_should_add_components_to_response() {
101     Operation result = searchResponseFormat.formatOperation(searchResponseData);
102
103     assertThat(result.getComponentsList()).hasSize(1);
104     assertThat(result.getComponentsList().get(0).getKey()).isEqualTo(issueDto.getComponentKey());
105   }
106
107   @Test
108   public void formatOperation_should_add_rules_to_response() {
109     Operation result = searchResponseFormat.formatOperation(searchResponseData);
110
111     assertThat(result.getRulesList()).hasSize(1);
112     assertThat(result.getRulesList().get(0).getKey()).isEqualTo(issueDto.getRuleKey().toString());
113   }
114
115   @Test
116   public void formatOperation_should_add_users_to_response() {
117     Operation result = searchResponseFormat.formatOperation(searchResponseData);
118
119     assertThat(result.getUsersList()).hasSize(1);
120     assertThat(result.getUsers(0)).isSameAs(user);
121   }
122
123   @Test
124   public void formatOperation_should_add_issue_to_response() {
125     Operation result = searchResponseFormat.formatOperation(searchResponseData);
126
127     assertIssueEqualsIssueDto(result.getIssue(), issueDto);
128   }
129
130   private void assertIssueEqualsIssueDto(Issue issue, IssueDto issueDto) {
131     assertThat(issue.getKey()).isEqualTo(issueDto.getKey());
132     assertThat(issue.getType().getNumber()).isEqualTo(issueDto.getType());
133     assertThat(issue.getComponent()).isEqualTo(issueDto.getComponentKey());
134     assertThat(issue.getRule()).isEqualTo(issueDto.getRuleKey().toString());
135     assertThat(issue.getSeverity()).hasToString(issueDto.getSeverity());
136     assertThat(issue.getAssignee()).isEqualTo(userDto.getLogin());
137     assertThat(issue.getResolution()).isEqualTo(issueDto.getResolution());
138     assertThat(issue.getStatus()).isEqualTo(issueDto.getStatus());
139     assertThat(issue.getMessage()).isEqualTo(issueDto.getMessage());
140     assertThat(new ArrayList<>(issue.getTagsList())).containsExactlyInAnyOrderElementsOf(issueDto.getTags());
141     assertThat(issue.getLine()).isEqualTo(issueDto.getLine());
142     assertThat(issue.getHash()).isEqualTo(issueDto.getChecksum());
143     assertThat(issue.getAuthor()).isEqualTo(issueDto.getAuthorLogin());
144     assertThat(issue.getCreationDate()).isEqualTo(formatDateTime(issueDto.getIssueCreationDate()));
145     assertThat(issue.getUpdateDate()).isEqualTo(formatDateTime(issueDto.getIssueUpdateDate()));
146     assertThat(issue.getCloseDate()).isEqualTo(formatDateTime(issueDto.getIssueCloseDate()));
147     assertThat(issue.getQuickFixAvailable()).isEqualTo(issueDto.isQuickFixAvailable());
148     assertThat(issue.getRuleDescriptionContextKey()).isEqualTo(issueDto.getOptionalRuleDescriptionContextKey().orElse(null));
149   }
150
151   @Test
152   public void formatOperation_should_not_add_issue_when_several_issue() {
153     searchResponseData = new SearchResponseData(List.of(createIssue(), createIssue()));
154
155     Operation result = searchResponseFormat.formatOperation(searchResponseData);
156
157     assertThat(result.getIssue()).isEqualTo(Issue.getDefaultInstance());
158   }
159
160   private static IssueDto createIssue() {
161     RuleDto ruleDto = newRule();
162     String projectUuid = "project_uuid_" + randomAlphanumeric(5);
163     ComponentDto projectDto = newPrivateProjectDto();
164     projectDto.setBranchUuid(projectUuid);
165     return newIssue(ruleDto, projectUuid, "project_key_" + randomAlphanumeric(5), projectDto);
166   }
167
168   @Test
169   public void formatOperation_should_add_branch_on_issue() {
170     componentDto.setKey(randomAlphanumeric(5) + BRANCH_KEY_SEPARATOR + randomAlphanumeric(5));
171
172     Operation result = searchResponseFormat.formatOperation(searchResponseData);
173
174     assertThat(result.getIssue().getBranch()).isEqualTo(componentDto.getBranch());
175   }
176
177   @Test
178   public void formatOperation_should_add_pullrequest_on_issue() {
179     String pullRequestKey = randomAlphanumeric(5);
180     componentDto.setKey(randomAlphanumeric(5) + PULL_REQUEST_SEPARATOR + pullRequestKey);
181
182     Operation result = searchResponseFormat.formatOperation(searchResponseData);
183
184     assertThat(result.getIssue().getPullRequest()).isEqualTo(pullRequestKey);
185   }
186
187   @Test
188   public void formatOperation_should_add_project_on_issue() {
189     issueDto.setProjectUuid(componentDto.uuid());
190
191     Operation result = searchResponseFormat.formatOperation(searchResponseData);
192
193     assertThat(result.getIssue().getProject()).isEqualTo(componentDto.getKey());
194   }
195
196   @Test
197   public void formatOperation_should_add_external_rule_engine_on_issue() {
198     issueDto.setExternal(true);
199     String expected = randomAlphanumeric(5);
200     issueDto.setRuleKey(EXTERNAL_RULE_REPO_PREFIX + expected, randomAlphanumeric(5));
201
202     Operation result = searchResponseFormat.formatOperation(searchResponseData);
203
204     assertThat(result.getIssue().getExternalRuleEngine()).isEqualTo(expected);
205   }
206
207   @Test
208   public void formatOperation_should_add_effort_and_debt_on_issue() {
209     long effort = 60L;
210     issueDto.setEffort(effort);
211     String expected = durations.encode(Duration.create(effort));
212
213     Operation result = searchResponseFormat.formatOperation(searchResponseData);
214
215     assertThat(result.getIssue().getEffort()).isEqualTo(expected);
216     assertThat(result.getIssue().getDebt()).isEqualTo(expected);
217   }
218
219   @Test
220   public void formatOperation_should_add_scope_test_on_issue_when_unit_test_file() {
221     componentDto.setQualifier(UNIT_TEST_FILE);
222
223     Operation result = searchResponseFormat.formatOperation(searchResponseData);
224
225     assertThat(result.getIssue().getScope()).isEqualTo(TEST.name());
226   }
227
228   @Test
229   public void formatOperation_should_add_scope_main_on_issue_when_not_unit_test_file() {
230     componentDto.setQualifier(randomAlphanumeric(5));
231
232     Operation result = searchResponseFormat.formatOperation(searchResponseData);
233
234     assertThat(result.getIssue().getScope()).isEqualTo(MAIN.name());
235   }
236
237   @Test
238   public void formatOperation_should_add_actions_on_issues() {
239     Set<String> expectedActions = Set.of("actionA", "actionB");
240     searchResponseData.addActions(issueDto.getKey(), expectedActions);
241
242     Operation result = searchResponseFormat.formatOperation(searchResponseData);
243
244     assertThat(result.getIssue().getActions().getActionsList()).containsExactlyInAnyOrderElementsOf(expectedActions);
245   }
246
247   @Test
248   public void formatOperation_should_add_transitions_on_issues() {
249     Set<String> expectedTransitions = Set.of("transitionone", "transitiontwo");
250     searchResponseData.addTransitions(issueDto.getKey(), createFakeTransitions(expectedTransitions));
251
252     Operation result = searchResponseFormat.formatOperation(searchResponseData);
253
254     assertThat(result.getIssue().getTransitions().getTransitionsList()).containsExactlyInAnyOrderElementsOf(expectedTransitions);
255   }
256
257   private static List<Transition> createFakeTransitions(Collection<String> transitions) {
258     return transitions.stream()
259       .map(transition -> Transition.builder(transition).from("OPEN").to("RESOLVED").build())
260       .collect(toList());
261   }
262
263   @Test
264   public void formatOperation_should_add_comments_on_issues() {
265     IssueChangeDto issueChangeDto = newIssuechangeDto(issueDto);
266     searchResponseData.setComments(List.of(issueChangeDto));
267
268     Operation result = searchResponseFormat.formatOperation(searchResponseData);
269
270     assertThat(result.getIssue().getComments().getCommentsList()).hasSize(1).extracting(Common.Comment::getKey).containsExactly(issueChangeDto.getKey());
271   }
272
273   @Test
274   public void formatOperation_should_not_set_severity_for_security_hotspot_issue() {
275     issueDto.setType(SECURITY_HOTSPOT);
276
277     Operation result = searchResponseFormat.formatOperation(searchResponseData);
278
279     assertThat(result.getIssue().hasSeverity()).isFalse();
280   }
281
282   private static SearchResponseData newSearchResponseData() {
283     RuleDto ruleDto = newRule();
284
285     String projectUuid = "project_uuid_" + randomAlphanumeric(5);
286     ComponentDto projectDto = newPrivateProjectDto();
287     projectDto.setBranchUuid(projectUuid);
288
289     UserDto userDto = newUserDto();
290
291     IssueDto issueDto = newIssue(ruleDto, projectUuid, "project_key_" + randomAlphanumeric(5), projectDto)
292       .setType(CODE_SMELL)
293       .setRuleDescriptionContextKey("context_key_" + randomAlphanumeric(5))
294       .setAssigneeUuid(userDto.getUuid())
295       .setResolution("resolution_" + randomAlphanumeric(5))
296       .setIssueCreationDate(new Date(currentTimeMillis() - 2_000))
297       .setIssueUpdateDate(new Date(currentTimeMillis() - 1_000))
298       .setIssueCloseDate(new Date(currentTimeMillis()));
299
300     SearchResponseData searchResponseData = new SearchResponseData(issueDto);
301     searchResponseData.addComponents(List.of(projectDto));
302     searchResponseData.addRules(List.of(ruleDto));
303     searchResponseData.addUsers(List.of(userDto));
304     return searchResponseData;
305   }
306
307 }