You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ShowActionTest.java 44KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2021 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.hotspot.ws;
  21. import com.google.common.collect.ImmutableSet;
  22. import com.google.common.collect.Sets;
  23. import com.tngtech.java.junit.dataprovider.DataProvider;
  24. import com.tngtech.java.junit.dataprovider.DataProviderRunner;
  25. import com.tngtech.java.junit.dataprovider.UseDataProvider;
  26. import java.util.Arrays;
  27. import java.util.Collections;
  28. import java.util.List;
  29. import java.util.Random;
  30. import java.util.Set;
  31. import java.util.function.Consumer;
  32. import java.util.stream.Collectors;
  33. import java.util.stream.IntStream;
  34. import java.util.stream.Stream;
  35. import javax.annotation.Nullable;
  36. import org.assertj.core.groups.Tuple;
  37. import org.junit.Before;
  38. import org.junit.Rule;
  39. import org.junit.Test;
  40. import org.junit.runner.RunWith;
  41. import org.mockito.ArgumentMatcher;
  42. import org.mockito.Mockito;
  43. import org.sonar.api.issue.Issue;
  44. import org.sonar.api.rules.RuleType;
  45. import org.sonar.api.utils.System2;
  46. import org.sonar.api.web.UserRole;
  47. import org.sonar.db.DbClient;
  48. import org.sonar.db.DbSession;
  49. import org.sonar.db.DbTester;
  50. import org.sonar.db.component.BranchType;
  51. import org.sonar.db.component.ComponentDto;
  52. import org.sonar.db.issue.IssueDto;
  53. import org.sonar.db.protobuf.DbCommons;
  54. import org.sonar.db.protobuf.DbIssues;
  55. import org.sonar.db.rule.RuleDefinitionDto;
  56. import org.sonar.db.rule.RuleTesting;
  57. import org.sonar.db.user.UserDto;
  58. import org.sonar.db.user.UserTesting;
  59. import org.sonar.server.es.EsTester;
  60. import org.sonar.server.exceptions.ForbiddenException;
  61. import org.sonar.server.exceptions.NotFoundException;
  62. import org.sonar.server.issue.AvatarResolver;
  63. import org.sonar.server.issue.AvatarResolverImpl;
  64. import org.sonar.server.issue.IssueChangeWSSupport;
  65. import org.sonar.server.issue.IssueChangeWSSupport.FormattingContext;
  66. import org.sonar.server.issue.IssueChangeWSSupport.Load;
  67. import org.sonar.server.issue.TextRangeResponseFormatter;
  68. import org.sonar.server.issue.ws.UserResponseFormatter;
  69. import org.sonar.server.security.SecurityStandards;
  70. import org.sonar.server.security.SecurityStandards.SQCategory;
  71. import org.sonar.server.tester.UserSessionRule;
  72. import org.sonar.server.text.MacroInterpreter;
  73. import org.sonar.server.ws.TestRequest;
  74. import org.sonar.server.ws.WsActionTester;
  75. import org.sonarqube.ws.Common;
  76. import org.sonarqube.ws.Common.Changelog.Diff;
  77. import org.sonarqube.ws.Common.User;
  78. import org.sonarqube.ws.Hotspots;
  79. import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
  80. import static org.assertj.core.api.Assertions.assertThat;
  81. import static org.assertj.core.api.Assertions.assertThatThrownBy;
  82. import static org.assertj.core.api.Assertions.tuple;
  83. import static org.mockito.ArgumentMatchers.any;
  84. import static org.mockito.ArgumentMatchers.anySet;
  85. import static org.mockito.ArgumentMatchers.anyString;
  86. import static org.mockito.ArgumentMatchers.argThat;
  87. import static org.mockito.ArgumentMatchers.eq;
  88. import static org.mockito.Mockito.doReturn;
  89. import static org.mockito.Mockito.mock;
  90. import static org.mockito.Mockito.verify;
  91. import static org.mockito.Mockito.verifyNoInteractions;
  92. import static org.mockito.Mockito.when;
  93. import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT;
  94. import static org.sonar.db.component.ComponentTesting.newFileDto;
  95. import static org.sonar.db.rule.RuleDto.Format.MARKDOWN;
  96. @RunWith(DataProviderRunner.class)
  97. public class ShowActionTest {
  98. private static final Random RANDOM = new Random();
  99. private static final String INTERPRETED = "interpreted";
  100. @Rule
  101. public DbTester dbTester = DbTester.create(System2.INSTANCE);
  102. @Rule
  103. public EsTester es = EsTester.create();
  104. @Rule
  105. public UserSessionRule userSessionRule = UserSessionRule.standalone();
  106. private final DbClient dbClient = dbTester.getDbClient();
  107. private final MacroInterpreter macroInterpreter = mock(MacroInterpreter.class);
  108. private final AvatarResolver avatarResolver = new AvatarResolverImpl();
  109. private final HotspotWsResponseFormatter responseFormatter = new HotspotWsResponseFormatter();
  110. private final IssueChangeWSSupport issueChangeSupport = Mockito.mock(IssueChangeWSSupport.class);
  111. private final HotspotWsSupport hotspotWsSupport = new HotspotWsSupport(dbClient, userSessionRule, System2.INSTANCE);
  112. private final UserResponseFormatter userFormatter = new UserResponseFormatter(new AvatarResolverImpl());
  113. private final TextRangeResponseFormatter textRangeFormatter = new TextRangeResponseFormatter();
  114. private final ShowAction underTest = new ShowAction(dbClient, hotspotWsSupport, responseFormatter, textRangeFormatter, userFormatter, issueChangeSupport, macroInterpreter);
  115. private final WsActionTester actionTester = new WsActionTester(underTest);
  116. @Before
  117. public void before() {
  118. doReturn(INTERPRETED).when(macroInterpreter).interpret(anyString());
  119. }
  120. @Test
  121. public void ws_is_public() {
  122. assertThat(actionTester.getDef().isInternal()).isFalse();
  123. }
  124. @Test
  125. public void fails_with_IAE_if_parameter_hotspot_is_missing() {
  126. TestRequest request = actionTester.newRequest();
  127. assertThatThrownBy(request::execute)
  128. .isInstanceOf(IllegalArgumentException.class)
  129. .hasMessage("The 'hotspot' parameter is missing");
  130. }
  131. @Test
  132. public void fails_with_NotFoundException_if_hotspot_does_not_exist() {
  133. String key = randomAlphabetic(12);
  134. TestRequest request = actionTester.newRequest()
  135. .setParam("hotspot", key);
  136. assertThatThrownBy(request::execute)
  137. .isInstanceOf(NotFoundException.class)
  138. .hasMessage("Hotspot '%s' does not exist", key);
  139. }
  140. @Test
  141. @UseDataProvider("ruleTypesButHotspot")
  142. public void fails_with_NotFoundException_if_issue_is_not_a_hotspot(RuleType ruleType) {
  143. ComponentDto project = dbTester.components().insertPublicProject();
  144. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  145. RuleDefinitionDto rule = newRule(ruleType);
  146. IssueDto notAHotspot = dbTester.issues().insertIssue(rule, project, file, i -> i.setType(ruleType));
  147. TestRequest request = newRequest(notAHotspot);
  148. assertThatThrownBy(request::execute)
  149. .isInstanceOf(NotFoundException.class)
  150. .hasMessage("Hotspot '%s' does not exist", notAHotspot.getKey());
  151. }
  152. @DataProvider
  153. public static Object[][] ruleTypesButHotspot() {
  154. return Arrays.stream(RuleType.values())
  155. .filter(t -> t != SECURITY_HOTSPOT)
  156. .map(t -> new Object[] {t})
  157. .toArray(Object[][]::new);
  158. }
  159. @Test
  160. public void fails_with_NotFoundException_if_issue_is_hotspot_is_closed() {
  161. ComponentDto project = dbTester.components().insertPublicProject();
  162. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  163. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  164. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file, t -> t.setStatus(Issue.STATUS_CLOSED));
  165. TestRequest request = newRequest(hotspot);
  166. assertThatThrownBy(request::execute)
  167. .isInstanceOf(NotFoundException.class)
  168. .hasMessage("Hotspot '%s' does not exist", hotspot.getKey());
  169. }
  170. @Test
  171. public void fails_with_ForbiddenException_if_project_is_private_and_not_allowed() {
  172. ComponentDto project = dbTester.components().insertPrivateProject();
  173. userSessionRule.registerComponents(project);
  174. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  175. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  176. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
  177. TestRequest request = newRequest(hotspot);
  178. assertThatThrownBy(request::execute)
  179. .isInstanceOf(ForbiddenException.class)
  180. .hasMessage("Insufficient privileges");
  181. }
  182. @Test
  183. public void succeeds_on_public_project() {
  184. ComponentDto project = dbTester.components().insertPublicProject();
  185. userSessionRule.registerComponents(project);
  186. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  187. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  188. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
  189. mockChangelogAndCommentsFormattingContext();
  190. Hotspots.ShowWsResponse response = newRequest(hotspot)
  191. .executeProtobuf(Hotspots.ShowWsResponse.class);
  192. assertThat(response.getKey()).isEqualTo(hotspot.getKey());
  193. }
  194. @Test
  195. public void succeeds_on_private_project_with_permission() {
  196. ComponentDto project = dbTester.components().insertPrivateProject();
  197. userSessionRule.registerComponents(project);
  198. userSessionRule.logIn().addProjectPermission(UserRole.USER, project);
  199. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  200. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  201. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
  202. mockChangelogAndCommentsFormattingContext();
  203. Hotspots.ShowWsResponse response = newRequest(hotspot)
  204. .executeProtobuf(Hotspots.ShowWsResponse.class);
  205. assertThat(response.getKey()).isEqualTo(hotspot.getKey());
  206. }
  207. @Test
  208. public void return_canChangeStatus_false_on_public_project_when_anonymous() {
  209. ComponentDto project = dbTester.components().insertPublicProject();
  210. userSessionRule.registerComponents(project);
  211. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  212. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  213. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
  214. mockChangelogAndCommentsFormattingContext();
  215. Hotspots.ShowWsResponse response = newRequest(hotspot)
  216. .executeProtobuf(Hotspots.ShowWsResponse.class);
  217. assertThat(response.getCanChangeStatus()).isFalse();
  218. }
  219. @Test
  220. @UseDataProvider("allPublicProjectPermissionsButSECURITYHOTSPOT_ADMIN")
  221. public void return_canChangeStatus_false_on_public_project_when_authenticated_without_SECURITYHOTSPOT_ADMIN_permission(@Nullable String permission) {
  222. ComponentDto project = dbTester.components().insertPublicProject();
  223. userSessionRule.logIn().registerComponents(project);
  224. if (permission != null) {
  225. userSessionRule.addProjectPermission(permission, project);
  226. }
  227. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  228. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  229. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
  230. mockChangelogAndCommentsFormattingContext();
  231. Hotspots.ShowWsResponse response = newRequest(hotspot)
  232. .executeProtobuf(Hotspots.ShowWsResponse.class);
  233. assertThat(response.getCanChangeStatus()).isFalse();
  234. }
  235. @Test
  236. @UseDataProvider("allPublicProjectPermissionsButSECURITYHOTSPOT_ADMIN")
  237. public void return_canChangeStatus_true_on_public_project_when_authenticated_with_SECURITYHOTSPOT_ADMIN_permission(@Nullable String permission) {
  238. ComponentDto project = dbTester.components().insertPublicProject();
  239. userSessionRule.registerComponents(project)
  240. .addProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN, project);
  241. if (permission != null) {
  242. userSessionRule.addProjectPermission(permission, project);
  243. }
  244. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  245. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  246. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
  247. mockChangelogAndCommentsFormattingContext();
  248. Hotspots.ShowWsResponse response = newRequest(hotspot)
  249. .executeProtobuf(Hotspots.ShowWsResponse.class);
  250. assertThat(response.getCanChangeStatus()).isTrue();
  251. }
  252. @DataProvider
  253. public static Object[][] allPublicProjectPermissionsButSECURITYHOTSPOT_ADMIN() {
  254. return new Object[][] {
  255. {null}, // no permission
  256. {UserRole.ADMIN},
  257. {UserRole.SCAN},
  258. {UserRole.ISSUE_ADMIN}
  259. };
  260. }
  261. @Test
  262. @UseDataProvider("allPrivateProjectPermissionsButSECURITYHOTSPOT_ADMIN_and_USER")
  263. public void return_canChangeStatus_false_on_private_project_without_SECURITYHOTSPOT_ADMIN_permission(@Nullable String permission) {
  264. ComponentDto project = dbTester.components().insertPrivateProject();
  265. userSessionRule
  266. .registerComponents(project)
  267. .logIn()
  268. .addProjectPermission(UserRole.USER, project);
  269. if (permission != null) {
  270. userSessionRule.addProjectPermission(permission, project);
  271. }
  272. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  273. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  274. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
  275. mockChangelogAndCommentsFormattingContext();
  276. Hotspots.ShowWsResponse response = newRequest(hotspot)
  277. .executeProtobuf(Hotspots.ShowWsResponse.class);
  278. assertThat(response.getCanChangeStatus()).isFalse();
  279. }
  280. @Test
  281. @UseDataProvider("allPrivateProjectPermissionsButSECURITYHOTSPOT_ADMIN_and_USER")
  282. public void return_canChangeStatus_false_on_private_project_with_SECURITYHOTSPOT_ADMIN_permission(@Nullable String permission) {
  283. ComponentDto project = dbTester.components().insertPrivateProject();
  284. userSessionRule
  285. .registerComponents(project)
  286. .logIn()
  287. .addProjectPermission(UserRole.USER, project)
  288. .addProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN, project);
  289. if (permission != null) {
  290. userSessionRule.addProjectPermission(permission, project);
  291. }
  292. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  293. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  294. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
  295. mockChangelogAndCommentsFormattingContext();
  296. Hotspots.ShowWsResponse response = newRequest(hotspot)
  297. .executeProtobuf(Hotspots.ShowWsResponse.class);
  298. assertThat(response.getCanChangeStatus()).isTrue();
  299. }
  300. @DataProvider
  301. public static Object[][] allPrivateProjectPermissionsButSECURITYHOTSPOT_ADMIN_and_USER() {
  302. return new Object[][] {
  303. {null}, // only USER permission
  304. {UserRole.CODEVIEWER},
  305. {UserRole.ADMIN},
  306. {UserRole.SCAN},
  307. {UserRole.ISSUE_ADMIN}
  308. };
  309. }
  310. @Test
  311. @UseDataProvider("statusAndResolutionCombinations")
  312. public void returns_status_and_resolution(String status, @Nullable String resolution) {
  313. ComponentDto project = dbTester.components().insertPrivateProject();
  314. userSessionRule.registerComponents(project);
  315. userSessionRule.logIn().addProjectPermission(UserRole.USER, project);
  316. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  317. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  318. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file, t -> t.setStatus(status).setResolution(resolution));
  319. mockChangelogAndCommentsFormattingContext();
  320. Hotspots.ShowWsResponse response = newRequest(hotspot)
  321. .executeProtobuf(Hotspots.ShowWsResponse.class);
  322. assertThat(response.getStatus()).isEqualTo(status);
  323. if (resolution == null) {
  324. assertThat(response.hasResolution()).isFalse();
  325. } else {
  326. assertThat(response.getResolution()).isEqualTo(resolution);
  327. }
  328. }
  329. @DataProvider
  330. public static Object[][] statusAndResolutionCombinations() {
  331. return new Object[][] {
  332. {Issue.STATUS_TO_REVIEW, null},
  333. {Issue.STATUS_REVIEWED, Issue.RESOLUTION_FIXED},
  334. {Issue.STATUS_REVIEWED, Issue.RESOLUTION_SAFE}
  335. };
  336. }
  337. @Test
  338. public void returns_html_description_for_custom_rules() {
  339. ComponentDto project = dbTester.components().insertPrivateProject();
  340. userSessionRule.registerComponents(project);
  341. userSessionRule.logIn().addProjectPermission(UserRole.USER, project);
  342. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  343. String description = "== Title\n<div>line1\nline2</div>";
  344. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT,
  345. r -> r.setTemplateUuid("123")
  346. .setDescription(description)
  347. .setDescriptionFormat(MARKDOWN));
  348. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
  349. mockChangelogAndCommentsFormattingContext();
  350. Hotspots.ShowWsResponse response = newRequest(hotspot)
  351. .executeProtobuf(Hotspots.ShowWsResponse.class);
  352. assertThat(response.getRule().getRiskDescription()).isEqualTo("<h2>Title</h2>&lt;div&gt;line1<br/>line2&lt;/div&gt;");
  353. }
  354. @Test
  355. public void handles_null_description_for_custom_rules() {
  356. ComponentDto project = dbTester.components().insertPrivateProject();
  357. userSessionRule.registerComponents(project);
  358. userSessionRule.logIn().addProjectPermission(UserRole.USER, project);
  359. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  360. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT, r -> r.setTemplateUuid("123").setDescription(null));
  361. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
  362. mockChangelogAndCommentsFormattingContext();
  363. Hotspots.ShowWsResponse response = newRequest(hotspot)
  364. .executeProtobuf(Hotspots.ShowWsResponse.class);
  365. assertThat(response.getRule().getRiskDescription()).isNullOrEmpty();
  366. verifyNoInteractions(macroInterpreter);
  367. }
  368. @Test
  369. public void returns_hotspot_component_and_rule() {
  370. ComponentDto project = dbTester.components().insertPublicProject();
  371. userSessionRule.registerComponents(project);
  372. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  373. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  374. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
  375. mockChangelogAndCommentsFormattingContext();
  376. Hotspots.ShowWsResponse response = newRequest(hotspot)
  377. .executeProtobuf(Hotspots.ShowWsResponse.class);
  378. assertThat(response.getKey()).isEqualTo(hotspot.getKey());
  379. verifyComponent(response.getComponent(), file, null, null);
  380. verifyComponent(response.getProject(), project, null, null);
  381. verifyRule(response.getRule(), rule);
  382. assertThat(response.hasTextRange()).isFalse();
  383. }
  384. @Test
  385. public void returns_no_textRange_when_locations_have_none() {
  386. ComponentDto project = dbTester.components().insertPublicProject();
  387. userSessionRule.registerComponents(project);
  388. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  389. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  390. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file,
  391. t -> t.setLocations(DbIssues.Locations.newBuilder().build()));
  392. mockChangelogAndCommentsFormattingContext();
  393. Hotspots.ShowWsResponse response = newRequest(hotspot)
  394. .executeProtobuf(Hotspots.ShowWsResponse.class);
  395. assertThat(response.hasTextRange()).isFalse();
  396. }
  397. @Test
  398. @UseDataProvider("randomTextRangeValues")
  399. public void returns_textRange(int startLine, int endLine, int startOffset, int endOffset) {
  400. ComponentDto project = dbTester.components().insertPublicProject();
  401. userSessionRule.registerComponents(project);
  402. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  403. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  404. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file,
  405. t -> t.setLocations(DbIssues.Locations.newBuilder()
  406. .setTextRange(DbCommons.TextRange.newBuilder()
  407. .setStartLine(startLine)
  408. .setEndLine(endLine)
  409. .setStartOffset(startOffset)
  410. .setEndOffset(endOffset)
  411. .build())
  412. .build()));
  413. mockChangelogAndCommentsFormattingContext();
  414. Hotspots.ShowWsResponse response = newRequest(hotspot)
  415. .executeProtobuf(Hotspots.ShowWsResponse.class);
  416. assertThat(response.hasTextRange()).isTrue();
  417. Common.TextRange textRange = response.getTextRange();
  418. assertThat(textRange.getStartLine()).isEqualTo(startLine);
  419. assertThat(textRange.getEndLine()).isEqualTo(endLine);
  420. assertThat(textRange.getStartOffset()).isEqualTo(startOffset);
  421. assertThat(textRange.getEndOffset()).isEqualTo(endOffset);
  422. }
  423. @Test
  424. public void returns_no_assignee_when_user_does_not_exist() {
  425. ComponentDto project = dbTester.components().insertPublicProject();
  426. userSessionRule.registerComponents(project);
  427. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  428. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  429. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file, t -> t.setAssigneeUuid(randomAlphabetic(10)));
  430. mockChangelogAndCommentsFormattingContext();
  431. Hotspots.ShowWsResponse response = newRequest(hotspot)
  432. .executeProtobuf(Hotspots.ShowWsResponse.class);
  433. assertThat(response.hasAssignee()).isFalse();
  434. }
  435. @Test
  436. public void returns_assignee_details_when_user_exists() {
  437. ComponentDto project = dbTester.components().insertPublicProject();
  438. userSessionRule.registerComponents(project);
  439. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  440. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  441. UserDto assignee = dbTester.users().insertUser();
  442. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file, t -> t.setAssigneeUuid(assignee.getUuid()));
  443. mockChangelogAndCommentsFormattingContext();
  444. Hotspots.ShowWsResponse response = newRequest(hotspot)
  445. .executeProtobuf(Hotspots.ShowWsResponse.class);
  446. assertThat(response.getAssignee()).isEqualTo(assignee.getLogin());
  447. assertThat(response.getUsersList()).hasSize(1);
  448. User wsAssignee = response.getUsersList().iterator().next();
  449. assertThat(wsAssignee.getLogin()).isEqualTo(assignee.getLogin());
  450. assertThat(wsAssignee.getName()).isEqualTo(assignee.getName());
  451. assertThat(wsAssignee.getActive()).isEqualTo(assignee.isActive());
  452. assertThat(wsAssignee.getAvatar()).isEqualTo(avatarResolver.create(assignee));
  453. }
  454. @Test
  455. public void returns_no_avatar_if_assignee_has_no_email() {
  456. ComponentDto project = dbTester.components().insertPublicProject();
  457. userSessionRule.registerComponents(project);
  458. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  459. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  460. UserDto assignee = dbTester.users().insertUser(t -> t.setEmail(null));
  461. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file, t -> t.setAssigneeUuid(assignee.getUuid()));
  462. mockChangelogAndCommentsFormattingContext();
  463. Hotspots.ShowWsResponse response = newRequest(hotspot)
  464. .executeProtobuf(Hotspots.ShowWsResponse.class);
  465. assertThat(response.getUsersList()).hasSize(1);
  466. assertThat(response.getUsersList().iterator().next().hasAvatar()).isFalse();
  467. }
  468. @Test
  469. public void returns_inactive_when_assignee_is_inactive() {
  470. ComponentDto project = dbTester.components().insertPublicProject();
  471. userSessionRule.registerComponents(project);
  472. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  473. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  474. UserDto assignee = dbTester.users().insertUser(t -> t.setActive(false));
  475. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file, t -> t.setAssigneeUuid(assignee.getUuid()));
  476. mockChangelogAndCommentsFormattingContext();
  477. Hotspots.ShowWsResponse response = newRequest(hotspot)
  478. .executeProtobuf(Hotspots.ShowWsResponse.class);
  479. assertThat(response.getUsersList()).hasSize(1);
  480. assertThat(response.getUsersList().iterator().next().getActive()).isFalse();
  481. }
  482. @Test
  483. public void returns_author_login_when_user_does_not_exist() {
  484. ComponentDto project = dbTester.components().insertPublicProject();
  485. userSessionRule.registerComponents(project);
  486. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  487. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  488. String authorLogin = randomAlphabetic(10);
  489. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file, t -> t.setAuthorLogin(authorLogin));
  490. mockChangelogAndCommentsFormattingContext();
  491. Hotspots.ShowWsResponse response = newRequest(hotspot)
  492. .executeProtobuf(Hotspots.ShowWsResponse.class);
  493. assertThat(response.getUsersList()).isEmpty();
  494. assertThat(response.getAuthor()).isEqualTo(authorLogin);
  495. }
  496. @Test
  497. public void returns_author_details_when_user_exists() {
  498. ComponentDto project = dbTester.components().insertPublicProject();
  499. userSessionRule.registerComponents(project);
  500. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  501. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  502. UserDto author = dbTester.users().insertUser();
  503. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file, t -> t.setAuthorLogin(author.getLogin()));
  504. mockChangelogAndCommentsFormattingContext();
  505. Hotspots.ShowWsResponse response = newRequest(hotspot)
  506. .executeProtobuf(Hotspots.ShowWsResponse.class);
  507. assertThat(response.getAuthor()).isEqualTo(author.getLogin());
  508. User wsAuthorFromList = response.getUsersList().iterator().next();
  509. assertThat(wsAuthorFromList.getLogin()).isEqualTo(author.getLogin());
  510. assertThat(wsAuthorFromList.getName()).isEqualTo(author.getName());
  511. assertThat(wsAuthorFromList.getActive()).isEqualTo(author.isActive());
  512. assertThat(wsAuthorFromList.getAvatar()).isEqualTo(avatarResolver.create(author));
  513. }
  514. @Test
  515. public void returns_no_avatar_if_author_has_no_email() {
  516. ComponentDto project = dbTester.components().insertPublicProject();
  517. userSessionRule.registerComponents(project);
  518. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  519. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  520. UserDto author = dbTester.users().insertUser(t -> t.setEmail(null));
  521. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file, t -> t.setAuthorLogin(author.getLogin()));
  522. mockChangelogAndCommentsFormattingContext();
  523. Hotspots.ShowWsResponse response = newRequest(hotspot)
  524. .executeProtobuf(Hotspots.ShowWsResponse.class);
  525. assertThat(response.getUsersList()).hasSize(1);
  526. assertThat(response.getUsersList().iterator().next().hasAvatar()).isFalse();
  527. }
  528. @Test
  529. public void returns_inactive_if_author_is_inactive() {
  530. ComponentDto project = dbTester.components().insertPublicProject();
  531. userSessionRule.registerComponents(project);
  532. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  533. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  534. UserDto author = dbTester.users().insertUser(t -> t.setActive(false));
  535. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file, t -> t.setAuthorLogin(author.getLogin()));
  536. mockChangelogAndCommentsFormattingContext();
  537. Hotspots.ShowWsResponse response = newRequest(hotspot)
  538. .executeProtobuf(Hotspots.ShowWsResponse.class);
  539. assertThat(response.getUsersList()).hasSize(1);
  540. assertThat(response.getUsersList().iterator().next().getActive()).isFalse();
  541. }
  542. @DataProvider
  543. public static Object[][] randomTextRangeValues() {
  544. int startLine = RANDOM.nextInt(200);
  545. int endLine = RANDOM.nextInt(200);
  546. int startOffset = RANDOM.nextInt(200);
  547. int endOffset = RANDOM.nextInt(200);
  548. return new Object[][] {
  549. {startLine, endLine, startOffset, endOffset}
  550. };
  551. }
  552. @Test
  553. public void returns_textRange_missing_fields() {
  554. ComponentDto project = dbTester.components().insertPublicProject();
  555. userSessionRule.registerComponents(project);
  556. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  557. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  558. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file,
  559. t -> t.setLocations(DbIssues.Locations.newBuilder()
  560. .setTextRange(DbCommons.TextRange.newBuilder().build())
  561. .build()));
  562. mockChangelogAndCommentsFormattingContext();
  563. Hotspots.ShowWsResponse response = newRequest(hotspot)
  564. .executeProtobuf(Hotspots.ShowWsResponse.class);
  565. assertThat(response.hasTextRange()).isTrue();
  566. Common.TextRange textRange = response.getTextRange();
  567. assertThat(textRange.hasStartLine()).isFalse();
  568. assertThat(textRange.hasEndLine()).isFalse();
  569. assertThat(textRange.hasStartOffset()).isFalse();
  570. assertThat(textRange.hasEndOffset()).isFalse();
  571. }
  572. @Test
  573. @UseDataProvider("allSQCategoryAndVulnerabilityProbability")
  574. public void returns_securityCategory_and_vulnerabilityProbability_of_rule(Set<String> standards,
  575. SQCategory expected) {
  576. ComponentDto project = dbTester.components().insertPublicProject();
  577. userSessionRule.registerComponents(project);
  578. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  579. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT, t -> t.setSecurityStandards(standards));
  580. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file,
  581. t -> t.setLocations(DbIssues.Locations.newBuilder()
  582. .setTextRange(DbCommons.TextRange.newBuilder().build())
  583. .build()));
  584. mockChangelogAndCommentsFormattingContext();
  585. Hotspots.ShowWsResponse response = newRequest(hotspot)
  586. .executeProtobuf(Hotspots.ShowWsResponse.class);
  587. Hotspots.Rule wsRule = response.getRule();
  588. assertThat(wsRule.getSecurityCategory()).isEqualTo(expected.getKey());
  589. assertThat(wsRule.getVulnerabilityProbability()).isEqualTo(expected.getVulnerability().name());
  590. }
  591. @DataProvider
  592. public static Object[][] allSQCategoryAndVulnerabilityProbability() {
  593. Stream<Object[]> allButOthers = SecurityStandards.CWES_BY_SQ_CATEGORY
  594. .entrySet()
  595. .stream()
  596. .map(t -> new Object[] {
  597. t.getValue().stream().map(s -> "cwe:" + s).collect(Collectors.toSet()),
  598. t.getKey()
  599. });
  600. Stream<Object[]> others = Stream.of(
  601. new Object[] {Collections.emptySet(), SQCategory.OTHERS},
  602. new Object[] {ImmutableSet.of("foo", "bar", "acme"), SQCategory.OTHERS});
  603. return Stream.concat(allButOthers, others)
  604. .toArray(Object[][]::new);
  605. }
  606. @Test
  607. public void returns_project_twice_when_hotspot_on_project() {
  608. ComponentDto project = dbTester.components().insertPublicProject();
  609. userSessionRule.registerComponents(project);
  610. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  611. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, project,
  612. t -> t.setLocations(DbIssues.Locations.newBuilder()
  613. .setTextRange(DbCommons.TextRange.newBuilder().build())
  614. .build()));
  615. mockChangelogAndCommentsFormattingContext();
  616. Hotspots.ShowWsResponse response = newRequest(hotspot)
  617. .executeProtobuf(Hotspots.ShowWsResponse.class);
  618. verifyComponent(response.getProject(), project, null, null);
  619. verifyComponent(response.getComponent(), project, null, null);
  620. }
  621. @Test
  622. public void returns_branch_but_no_pullRequest_on_component_and_project_on_non_main_branch() {
  623. ComponentDto project = dbTester.components().insertPublicProject();
  624. ComponentDto branch = dbTester.components().insertProjectBranch(project);
  625. ComponentDto file = dbTester.components().insertComponent(newFileDto(branch));
  626. userSessionRule.registerComponents(project);
  627. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  628. IssueDto hotspot = dbTester.issues().insertHotspot(rule, branch, file,
  629. t -> t.setLocations(DbIssues.Locations.newBuilder()
  630. .setTextRange(DbCommons.TextRange.newBuilder().build())
  631. .build()));
  632. mockChangelogAndCommentsFormattingContext();
  633. Hotspots.ShowWsResponse response = newRequest(hotspot)
  634. .executeProtobuf(Hotspots.ShowWsResponse.class);
  635. verifyComponent(response.getProject(), branch, branch.getBranch(), null);
  636. verifyComponent(response.getComponent(), file, branch.getBranch(), null);
  637. }
  638. @Test
  639. public void returns_pullRequest_but_no_branch_on_component_and_project_on_pullRequest() {
  640. ComponentDto project = dbTester.components().insertPublicProject();
  641. ComponentDto pullRequest = dbTester.components().insertProjectBranch(project,
  642. t -> t.setBranchType(BranchType.PULL_REQUEST));
  643. ComponentDto file = dbTester.components().insertComponent(newFileDto(pullRequest));
  644. userSessionRule.registerComponents(project);
  645. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  646. IssueDto hotspot = dbTester.issues().insertHotspot(rule, pullRequest, file,
  647. t -> t.setLocations(DbIssues.Locations.newBuilder()
  648. .setTextRange(DbCommons.TextRange.newBuilder().build())
  649. .build()));
  650. mockChangelogAndCommentsFormattingContext();
  651. Hotspots.ShowWsResponse response = newRequest(hotspot)
  652. .executeProtobuf(Hotspots.ShowWsResponse.class);
  653. verifyComponent(response.getProject(), pullRequest, null, pullRequest.getPullRequest());
  654. verifyComponent(response.getComponent(), file, null, pullRequest.getPullRequest());
  655. }
  656. @Test
  657. public void returns_hotspot_changelog_and_comments() {
  658. ComponentDto project = dbTester.components().insertPublicProject();
  659. userSessionRule.registerComponents(project);
  660. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  661. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  662. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file,
  663. t -> t.setLocations(DbIssues.Locations.newBuilder()
  664. .setTextRange(DbCommons.TextRange.newBuilder().build())
  665. .build()));
  666. List<Common.Changelog> changelog = IntStream.range(0, 1 + new Random().nextInt(12))
  667. .mapToObj(i -> Common.Changelog.newBuilder().setUser("u" + i).build())
  668. .collect(Collectors.toList());
  669. List<Common.Comment> comments = IntStream.range(0, 1 + new Random().nextInt(12))
  670. .mapToObj(i -> Common.Comment.newBuilder().setKey("u" + i).build())
  671. .collect(Collectors.toList());
  672. FormattingContext formattingContext = mockChangelogAndCommentsFormattingContext();
  673. when(issueChangeSupport.formatChangelog(any(), any())).thenReturn(changelog.stream());
  674. when(issueChangeSupport.formatComments(any(), any(), any())).thenReturn(comments.stream());
  675. Hotspots.ShowWsResponse response = newRequest(hotspot)
  676. .executeProtobuf(Hotspots.ShowWsResponse.class);
  677. assertThat(response.getChangelogList())
  678. .extracting(Common.Changelog::getUser)
  679. .containsExactly(changelog.stream().map(Common.Changelog::getUser).toArray(String[]::new));
  680. assertThat(response.getCommentList())
  681. .extracting(Common.Comment::getKey)
  682. .containsExactly(comments.stream().map(Common.Comment::getKey).toArray(String[]::new));
  683. verify(issueChangeSupport).newFormattingContext(any(DbSession.class),
  684. argThat(new IssueDtoSetArgumentMatcher(hotspot)),
  685. eq(Load.ALL),
  686. eq(Collections.emptySet()), eq(ImmutableSet.of(project, file)));
  687. verify(issueChangeSupport).formatChangelog(argThat(new IssueDtoArgumentMatcher(hotspot)), eq(formattingContext));
  688. verify(issueChangeSupport).formatComments(argThat(new IssueDtoArgumentMatcher(hotspot)), any(Common.Comment.Builder.class), eq(formattingContext));
  689. }
  690. @Test
  691. public void returns_user_details_of_users_from_ChangelogAndComments() {
  692. ComponentDto project = dbTester.components().insertPublicProject();
  693. userSessionRule.registerComponents(project);
  694. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  695. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  696. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
  697. FormattingContext formattingContext = mockChangelogAndCommentsFormattingContext();
  698. Set<UserDto> changeLogAndCommentsUsers = IntStream.range(0, 1 + RANDOM.nextInt(14))
  699. .mapToObj(i -> UserTesting.newUserDto())
  700. .collect(Collectors.toSet());
  701. when(formattingContext.getUsers()).thenReturn(changeLogAndCommentsUsers);
  702. Hotspots.ShowWsResponse response = newRequest(hotspot)
  703. .executeProtobuf(Hotspots.ShowWsResponse.class);
  704. assertThat(response.getUsersList())
  705. .extracting(User::getLogin, User::getName, User::getActive)
  706. .containsExactlyInAnyOrder(
  707. changeLogAndCommentsUsers.stream()
  708. .map(t -> tuple(t.getLogin(), t.getName(), t.isActive()))
  709. .toArray(Tuple[]::new));
  710. }
  711. @Test
  712. public void returns_user_of_users_from_ChangelogAndComments_and_assignee_and_author() {
  713. ComponentDto project = dbTester.components().insertPublicProject();
  714. userSessionRule.registerComponents(project);
  715. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  716. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  717. UserDto author = dbTester.users().insertUser();
  718. UserDto assignee = dbTester.users().insertUser();
  719. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file,
  720. t -> t.setAuthorLogin(author.getLogin())
  721. .setAssigneeUuid(assignee.getUuid()));
  722. FormattingContext formattingContext = mockChangelogAndCommentsFormattingContext();
  723. Set<UserDto> changeLogAndCommentsUsers = IntStream.range(0, 1 + RANDOM.nextInt(14))
  724. .mapToObj(i -> UserTesting.newUserDto())
  725. .collect(Collectors.toSet());
  726. when(formattingContext.getUsers()).thenReturn(changeLogAndCommentsUsers);
  727. Hotspots.ShowWsResponse response = newRequest(hotspot)
  728. .executeProtobuf(Hotspots.ShowWsResponse.class);
  729. assertThat(response.getUsersList())
  730. .extracting(User::getLogin, User::getName, User::getActive)
  731. .containsExactlyInAnyOrder(
  732. Stream.concat(
  733. Stream.of(author, assignee),
  734. changeLogAndCommentsUsers.stream())
  735. .map(t -> tuple(t.getLogin(), t.getName(), t.isActive()))
  736. .toArray(Tuple[]::new));
  737. }
  738. @Test
  739. public void do_not_duplicate_user_if_author_assignee_ChangeLogComment_user() {
  740. ComponentDto project = dbTester.components().insertPublicProject();
  741. userSessionRule.registerComponents(project);
  742. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
  743. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  744. UserDto author = dbTester.users().insertUser();
  745. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file,
  746. t -> t.setAuthorLogin(author.getLogin())
  747. .setAssigneeUuid(author.getUuid()));
  748. FormattingContext formattingContext = mockChangelogAndCommentsFormattingContext();
  749. when(formattingContext.getUsers()).thenReturn(ImmutableSet.of(author));
  750. Hotspots.ShowWsResponse response = newRequest(hotspot)
  751. .executeProtobuf(Hotspots.ShowWsResponse.class);
  752. assertThat(response.getUsersList())
  753. .extracting(User::getLogin, User::getName, User::getActive)
  754. .containsOnly(tuple(author.getLogin(), author.getName(), author.isActive()));
  755. }
  756. @Test
  757. public void verify_response_example() {
  758. ComponentDto project = dbTester.components().insertPublicProject(componentDto -> componentDto
  759. .setName("test-project")
  760. .setLongName("test-project")
  761. .setDbKey("com.sonarsource:test-project"));
  762. userSessionRule.registerComponents(project)
  763. .addProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN, project);
  764. ComponentDto file = dbTester.components().insertComponent(
  765. newFileDto(project)
  766. .setDbKey("com.sonarsource:test-project:src/main/java/com/sonarsource/FourthClass.java")
  767. .setName("FourthClass.java")
  768. .setLongName("src/main/java/com/sonarsource/FourthClass.java")
  769. .setPath("src/main/java/com/sonarsource/FourthClass.java"));
  770. UserDto author = dbTester.users().insertUser(u -> u.setLogin("joe")
  771. .setName("Joe"));
  772. long time = 1577976190000L;
  773. RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT, r -> r.setRuleKey("S4787")
  774. .setRepositoryKey("java")
  775. .setName("rule-name")
  776. .setSecurityStandards(Sets.newHashSet(SQCategory.WEAK_CRYPTOGRAPHY.getKey())));
  777. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file, h -> h
  778. .setAssigneeUuid("assignee-uuid")
  779. .setAuthorLogin("joe")
  780. .setMessage("message")
  781. .setLine(10)
  782. .setChecksum("a227e508d6646b55a086ee11d63b21e9")
  783. .setIssueCreationTime(time)
  784. .setIssueUpdateTime(time)
  785. .setAuthorLogin(author.getLogin())
  786. .setAssigneeUuid(author.getUuid())
  787. .setKee("AW9mgJw6eFC3pGl94Wrf"));
  788. List<Common.Changelog> changelog = IntStream.range(0, 3)
  789. .mapToObj(i -> Common.Changelog.newBuilder()
  790. .setUser("joe")
  791. .setCreationDate("2020-01-02T14:44:55+0100")
  792. .addDiffs(Diff.newBuilder().setKey("diff-key-" + i).setNewValue("new-value-" + i).setOldValue("old-value-" + i))
  793. .setIsUserActive(true)
  794. .setUserName("Joe")
  795. .setAvatar("my-avatar")
  796. .build())
  797. .collect(Collectors.toList());
  798. List<Common.Comment> comments = IntStream.range(0, 3)
  799. .mapToObj(i -> Common.Comment.newBuilder()
  800. .setKey("comment-" + i)
  801. .setHtmlText("html text " + i)
  802. .setLogin("Joe")
  803. .setMarkdown("markdown " + i)
  804. .setCreatedAt("2020-01-02T14:47:47+0100")
  805. .build())
  806. .collect(Collectors.toList());
  807. mockChangelogAndCommentsFormattingContext();
  808. when(issueChangeSupport.formatChangelog(any(), any())).thenReturn(changelog.stream());
  809. when(issueChangeSupport.formatComments(any(), any(), any())).thenReturn(comments.stream());
  810. assertThat(actionTester.getDef().responseExampleAsString()).isNotNull();
  811. newRequest(hotspot)
  812. .execute()
  813. .assertJson(actionTester.getDef().responseExampleAsString());
  814. }
  815. private FormattingContext mockChangelogAndCommentsFormattingContext() {
  816. FormattingContext formattingContext = Mockito.mock(FormattingContext.class);
  817. when(issueChangeSupport.newFormattingContext(any(), any(), any(), anySet(), anySet())).thenReturn(formattingContext);
  818. return formattingContext;
  819. }
  820. private void verifyRule(Hotspots.Rule wsRule, RuleDefinitionDto dto) {
  821. assertThat(wsRule.getKey()).isEqualTo(dto.getKey().toString());
  822. assertThat(wsRule.getName()).isEqualTo(dto.getName());
  823. assertThat(wsRule.getSecurityCategory()).isEqualTo(SQCategory.OTHERS.getKey());
  824. assertThat(wsRule.getVulnerabilityProbability()).isEqualTo(SQCategory.OTHERS.getVulnerability().name());
  825. }
  826. private static void verifyComponent(Hotspots.Component wsComponent, ComponentDto dto, @Nullable String branch, @Nullable String pullRequest) {
  827. assertThat(wsComponent.getKey()).isEqualTo(dto.getKey());
  828. if (dto.path() == null) {
  829. assertThat(wsComponent.hasPath()).isFalse();
  830. } else {
  831. assertThat(wsComponent.getPath()).isEqualTo(dto.path());
  832. }
  833. assertThat(wsComponent.getQualifier()).isEqualTo(dto.qualifier());
  834. assertThat(wsComponent.getName()).isEqualTo(dto.name());
  835. assertThat(wsComponent.getLongName()).isEqualTo(dto.longName());
  836. if (branch == null) {
  837. assertThat(wsComponent.hasBranch()).isFalse();
  838. } else {
  839. assertThat(wsComponent.getBranch()).isEqualTo(branch);
  840. }
  841. if (pullRequest == null) {
  842. assertThat(wsComponent.hasPullRequest()).isFalse();
  843. } else {
  844. assertThat(wsComponent.getPullRequest()).isEqualTo(pullRequest);
  845. }
  846. }
  847. private TestRequest newRequest(IssueDto hotspot) {
  848. return actionTester.newRequest()
  849. .setParam("hotspot", hotspot.getKey());
  850. }
  851. private RuleDefinitionDto newRule(RuleType ruleType) {
  852. return newRule(ruleType, t -> {
  853. });
  854. }
  855. private RuleDefinitionDto newRule(RuleType ruleType, Consumer<RuleDefinitionDto> populate) {
  856. RuleDefinitionDto ruleDefinition = RuleTesting.newRule()
  857. .setType(ruleType);
  858. populate.accept(ruleDefinition);
  859. dbTester.rules().insert(ruleDefinition);
  860. return ruleDefinition;
  861. }
  862. private static class IssueDtoSetArgumentMatcher implements ArgumentMatcher<Set<IssueDto>> {
  863. private final IssueDto expected;
  864. private IssueDtoSetArgumentMatcher(IssueDto expected) {
  865. this.expected = expected;
  866. }
  867. @Override
  868. public boolean matches(Set<IssueDto> argument) {
  869. return argument != null && argument.size() == 1 && argument.iterator().next().getKey().equals(expected.getKey());
  870. }
  871. @Override
  872. public String toString() {
  873. return "Set<IssueDto>[" + expected.getKey() + "]";
  874. }
  875. }
  876. private static class IssueDtoArgumentMatcher implements ArgumentMatcher<IssueDto> {
  877. private final IssueDto expected;
  878. private IssueDtoArgumentMatcher(IssueDto expected) {
  879. this.expected = expected;
  880. }
  881. @Override
  882. public boolean matches(IssueDto argument) {
  883. return argument != null && argument.getKey().equals(expected.getKey());
  884. }
  885. @Override
  886. public String toString() {
  887. return "IssueDto[key=" + expected.getKey() + "]";
  888. }
  889. }
  890. }