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

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