選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

ShowActionIT.java 62KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2023 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.List;
  28. import java.util.Random;
  29. import java.util.Set;
  30. import java.util.function.Consumer;
  31. import java.util.function.Supplier;
  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.core.util.UuidFactory;
  47. import org.sonar.core.util.UuidFactoryFast;
  48. import org.sonar.db.DbClient;
  49. import org.sonar.db.DbSession;
  50. import org.sonar.db.DbTester;
  51. import org.sonar.db.component.BranchType;
  52. import org.sonar.db.component.ComponentDto;
  53. import org.sonar.db.component.ProjectData;
  54. import org.sonar.db.issue.IssueDto;
  55. import org.sonar.db.project.ProjectDto;
  56. import org.sonar.db.protobuf.DbCommons.TextRange;
  57. import org.sonar.db.protobuf.DbIssues;
  58. import org.sonar.db.protobuf.DbIssues.Flow;
  59. import org.sonar.db.protobuf.DbIssues.FlowType;
  60. import org.sonar.db.rule.RuleDescriptionSectionContextDto;
  61. import org.sonar.db.rule.RuleDescriptionSectionDto;
  62. import org.sonar.db.rule.RuleDto;
  63. import org.sonar.db.rule.RuleTesting;
  64. import org.sonar.db.user.UserDto;
  65. import org.sonar.db.user.UserTesting;
  66. import org.sonar.server.es.EsTester;
  67. import org.sonar.server.exceptions.ForbiddenException;
  68. import org.sonar.server.exceptions.NotFoundException;
  69. import org.sonar.server.common.avatar.AvatarResolver;
  70. import org.sonar.server.common.avatar.AvatarResolverImpl;
  71. import org.sonar.server.issue.IssueChangeWSSupport;
  72. import org.sonar.server.issue.IssueChangeWSSupport.FormattingContext;
  73. import org.sonar.server.issue.IssueChangeWSSupport.Load;
  74. import org.sonar.server.issue.TextRangeResponseFormatter;
  75. import org.sonar.server.issue.ws.UserResponseFormatter;
  76. import org.sonar.server.security.SecurityStandards;
  77. import org.sonar.server.security.SecurityStandards.SQCategory;
  78. import org.sonar.server.tester.UserSessionRule;
  79. import org.sonar.server.ws.TestRequest;
  80. import org.sonar.server.ws.WsActionTester;
  81. import org.sonarqube.ws.Common;
  82. import org.sonarqube.ws.Common.Changelog.Diff;
  83. import org.sonarqube.ws.Common.Location;
  84. import org.sonarqube.ws.Common.User;
  85. import org.sonarqube.ws.Hotspots;
  86. import static java.util.Collections.emptySet;
  87. import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
  88. import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
  89. import static org.assertj.core.api.Assertions.assertThat;
  90. import static org.assertj.core.api.Assertions.assertThatThrownBy;
  91. import static org.assertj.core.api.Assertions.tuple;
  92. import static org.mockito.ArgumentMatchers.any;
  93. import static org.mockito.ArgumentMatchers.anySet;
  94. import static org.mockito.ArgumentMatchers.argThat;
  95. import static org.mockito.ArgumentMatchers.eq;
  96. import static org.mockito.Mockito.verify;
  97. import static org.mockito.Mockito.when;
  98. import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT;
  99. import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ASSESS_THE_PROBLEM_SECTION_KEY;
  100. import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.HOW_TO_FIX_SECTION_KEY;
  101. import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.INTRODUCTION_SECTION_KEY;
  102. import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.RESOURCES_SECTION_KEY;
  103. import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ROOT_CAUSE_SECTION_KEY;
  104. import static org.sonar.db.component.ComponentTesting.newFileDto;
  105. import static org.sonar.db.protobuf.DbIssues.MessageFormattingType.CODE;
  106. import static org.sonar.db.rule.RuleDescriptionSectionDto.DEFAULT_KEY;
  107. import static org.sonar.db.rule.RuleDto.Format.HTML;
  108. import static org.sonar.db.rule.RuleDto.Format.MARKDOWN;
  109. @RunWith(DataProviderRunner.class)
  110. public class ShowActionIT {
  111. private static final Random RANDOM = new Random();
  112. public static final DbIssues.MessageFormatting MESSAGE_FORMATTING = DbIssues.MessageFormatting.newBuilder().setStart(0).setEnd(4).setType(CODE).build();
  113. @Rule
  114. public DbTester dbTester = DbTester.create(System2.INSTANCE);
  115. @Rule
  116. public EsTester es = EsTester.create();
  117. @Rule
  118. public UserSessionRule userSessionRule = UserSessionRule.standalone();
  119. private final DbClient dbClient = dbTester.getDbClient();
  120. private final AvatarResolver avatarResolver = new AvatarResolverImpl();
  121. private final TextRangeResponseFormatter textRangeFormatter = new TextRangeResponseFormatter();
  122. private final HotspotWsResponseFormatter responseFormatter = new HotspotWsResponseFormatter(textRangeFormatter);
  123. private final IssueChangeWSSupport issueChangeSupport = Mockito.mock(IssueChangeWSSupport.class);
  124. private final HotspotWsSupport hotspotWsSupport = new HotspotWsSupport(dbClient, userSessionRule, System2.INSTANCE);
  125. private final UserResponseFormatter userFormatter = new UserResponseFormatter(new AvatarResolverImpl());
  126. private final ShowAction underTest = new ShowAction(dbClient, hotspotWsSupport, responseFormatter, userFormatter, issueChangeSupport);
  127. private final WsActionTester actionTester = new WsActionTester(underTest);
  128. private final UuidFactory uuidFactory = UuidFactoryFast.getInstance();
  129. @Test
  130. public void ws_is_public() {
  131. assertThat(actionTester.getDef().isInternal()).isFalse();
  132. }
  133. @Test
  134. public void fails_with_IAE_if_parameter_hotspot_is_missing() {
  135. TestRequest request = actionTester.newRequest();
  136. assertThatThrownBy(request::execute)
  137. .isInstanceOf(IllegalArgumentException.class)
  138. .hasMessage("The 'hotspot' parameter is missing");
  139. }
  140. @Test
  141. public void fails_with_NotFoundException_if_hotspot_does_not_exist() {
  142. String key = randomAlphabetic(12);
  143. TestRequest request = actionTester.newRequest()
  144. .setParam("hotspot", key);
  145. assertThatThrownBy(request::execute)
  146. .isInstanceOf(NotFoundException.class)
  147. .hasMessage("Hotspot '%s' does not exist", key);
  148. }
  149. @Test
  150. @UseDataProvider("ruleTypesButHotspot")
  151. public void fails_with_NotFoundException_if_issue_is_not_a_hotspot(RuleType ruleType) {
  152. ComponentDto mainBranchComponent = dbTester.components().insertPublicProject().getMainBranchComponent();
  153. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  154. RuleDto rule = newRule(ruleType);
  155. IssueDto notAHotspot = dbTester.issues().insertIssue(rule, mainBranchComponent, file, i -> i.setType(ruleType));
  156. TestRequest request = newRequest(notAHotspot);
  157. assertThatThrownBy(request::execute)
  158. .isInstanceOf(NotFoundException.class)
  159. .hasMessage("Hotspot '%s' does not exist", notAHotspot.getKey());
  160. }
  161. @DataProvider
  162. public static Object[][] ruleTypesButHotspot() {
  163. return Arrays.stream(RuleType.values())
  164. .filter(t -> t != SECURITY_HOTSPOT)
  165. .map(t -> new Object[] {t})
  166. .toArray(Object[][]::new);
  167. }
  168. @Test
  169. public void fails_with_NotFoundException_if_issue_is_hotspot_is_closed() {
  170. ComponentDto mainBranchComponent = dbTester.components().insertPublicProject().getMainBranchComponent();
  171. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  172. RuleDto rule = newRule(SECURITY_HOTSPOT);
  173. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setStatus(Issue.STATUS_CLOSED));
  174. TestRequest request = newRequest(hotspot);
  175. assertThatThrownBy(request::execute)
  176. .isInstanceOf(NotFoundException.class)
  177. .hasMessage("Hotspot '%s' does not exist", hotspot.getKey());
  178. }
  179. @Test
  180. public void fails_with_ForbiddenException_if_project_is_private_and_not_allowed() {
  181. ProjectData projectData = dbTester.components().insertPrivateProject();
  182. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  183. userSessionRule.registerProjects(projectData.getProjectDto());
  184. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  185. RuleDto rule = newRule(SECURITY_HOTSPOT);
  186. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
  187. TestRequest request = newRequest(hotspot);
  188. assertThatThrownBy(request::execute)
  189. .isInstanceOf(ForbiddenException.class)
  190. .hasMessage("Insufficient privileges");
  191. }
  192. @Test
  193. public void succeeds_on_hotspot_with_flow() {
  194. ProjectData projectData = dbTester.components().insertPublicProject();
  195. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  196. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  197. ComponentDto anotherFile = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  198. DbIssues.Locations.Builder locations = DbIssues.Locations.newBuilder()
  199. .addFlow(Flow.newBuilder()
  200. .setDescription("FLOW DESCRIPTION")
  201. .setType(FlowType.DATA)
  202. .addAllLocation(Arrays.asList(
  203. DbIssues.Location.newBuilder()
  204. .setComponentId(file.uuid())
  205. .setMsg("FLOW MESSAGE")
  206. .addMsgFormatting(MESSAGE_FORMATTING)
  207. .setTextRange(textRange(1, 1, 0, 12)).build(),
  208. DbIssues.Location.newBuilder()
  209. .setComponentId(anotherFile.uuid())
  210. .setMsg("ANOTHER FLOW MESSAGE")
  211. .setTextRange(textRange(1, 1, 0, 12)).build(),
  212. DbIssues.Location.newBuilder()
  213. .setMsg("FLOW MESSAGE WITHOUT FILE UUID")
  214. .setTextRange(textRange(1, 1, 0, 12)).build())))
  215. .addFlow(Flow.newBuilder()
  216. .addLocation(DbIssues.Location.newBuilder()
  217. .setComponentId(file.uuid())
  218. .setTextRange(TextRange.newBuilder().setStartLine(1).setStartOffset(0).setEndOffset(12).build())
  219. .build()))
  220. .addFlow(Flow.newBuilder()
  221. .setType(FlowType.EXECUTION)
  222. .addLocation(DbIssues.Location.newBuilder()
  223. .setComponentId(file.uuid())
  224. .build()));
  225. RuleDto rule = newRule(SECURITY_HOTSPOT);
  226. var hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, i -> i.setLocations(locations.build()));
  227. mockChangelogAndCommentsFormattingContext();
  228. userSessionRule.registerProjects(projectData.getProjectDto());
  229. Hotspots.ShowWsResponse response = newRequest(hotspot)
  230. .executeProtobuf(Hotspots.ShowWsResponse.class);
  231. assertThat(response.getKey()).isEqualTo(hotspot.getKey());
  232. assertThat(response.getFlowsCount()).isEqualTo(3);
  233. assertThat(response.getFlows(0).getDescription()).isEqualTo("FLOW DESCRIPTION");
  234. assertThat(response.getFlows(0).getType()).isEqualTo(Common.FlowType.DATA);
  235. assertThat(response.getFlows(0).getLocationsList())
  236. .extracting(Location::getMsg, Location::getMsgFormattingsList, Location::getComponent)
  237. .containsExactlyInAnyOrder(
  238. tuple("FLOW MESSAGE", List.of(Common.MessageFormatting.newBuilder()
  239. .setStart(0).setEnd(4).setType(Common.MessageFormattingType.CODE).build()), file.getKey()),
  240. tuple("ANOTHER FLOW MESSAGE", List.of(), anotherFile.getKey()),
  241. tuple("FLOW MESSAGE WITHOUT FILE UUID", List.of(), file.getKey()));
  242. assertThat(response.getFlows(1).getDescription()).isEmpty();
  243. assertThat(response.getFlows(1).hasType()).isFalse();
  244. assertThat(response.getFlows(2).getType()).isEqualTo(Common.FlowType.EXECUTION);
  245. }
  246. @Test
  247. public void succeeds_on_public_project() {
  248. ProjectData projectData = dbTester.components().insertPublicProject();
  249. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  250. userSessionRule.registerProjects(projectData.getProjectDto());
  251. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  252. RuleDto rule = newRule(SECURITY_HOTSPOT);
  253. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
  254. mockChangelogAndCommentsFormattingContext();
  255. Hotspots.ShowWsResponse response = newRequest(hotspot)
  256. .executeProtobuf(Hotspots.ShowWsResponse.class);
  257. assertThat(response.getKey()).isEqualTo(hotspot.getKey());
  258. }
  259. @Test
  260. public void succeeds_on_private_project_with_permission() {
  261. ProjectData projectData = dbTester.components().insertPrivateProject();
  262. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  263. userSessionRule.registerProjects(projectData.getProjectDto());
  264. userSessionRule.logIn().addProjectPermission(UserRole.USER, projectData.getProjectDto());
  265. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  266. RuleDto rule = newRule(SECURITY_HOTSPOT);
  267. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
  268. mockChangelogAndCommentsFormattingContext();
  269. Hotspots.ShowWsResponse response = newRequest(hotspot)
  270. .executeProtobuf(Hotspots.ShowWsResponse.class);
  271. assertThat(response.getKey()).isEqualTo(hotspot.getKey());
  272. }
  273. @Test
  274. public void return_canChangeStatus_false_on_public_project_when_anonymous() {
  275. ProjectData projectData = dbTester.components().insertPublicProject();
  276. ComponentDto project = projectData.getMainBranchComponent();
  277. userSessionRule.registerProjects(projectData.getProjectDto());
  278. ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
  279. RuleDto rule = newRule(SECURITY_HOTSPOT);
  280. IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
  281. mockChangelogAndCommentsFormattingContext();
  282. Hotspots.ShowWsResponse response = newRequest(hotspot)
  283. .executeProtobuf(Hotspots.ShowWsResponse.class);
  284. assertThat(response.getCanChangeStatus()).isFalse();
  285. }
  286. @Test
  287. @UseDataProvider("allPublicProjectPermissionsButSECURITYHOTSPOT_ADMIN")
  288. public void return_canChangeStatus_false_on_public_project_when_authenticated_without_SECURITYHOTSPOT_ADMIN_permission(@Nullable String permission) {
  289. ProjectData projectData = dbTester.components().insertPublicProject();
  290. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  291. userSessionRule.logIn().registerProjects(projectData.getProjectDto());
  292. if (permission != null) {
  293. userSessionRule.addProjectPermission(permission, projectData.getProjectDto());
  294. }
  295. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  296. RuleDto rule = newRule(SECURITY_HOTSPOT);
  297. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
  298. mockChangelogAndCommentsFormattingContext();
  299. Hotspots.ShowWsResponse response = newRequest(hotspot)
  300. .executeProtobuf(Hotspots.ShowWsResponse.class);
  301. assertThat(response.getCanChangeStatus()).isFalse();
  302. }
  303. @Test
  304. @UseDataProvider("allPublicProjectPermissionsButSECURITYHOTSPOT_ADMIN")
  305. public void return_canChangeStatus_true_on_public_project_when_authenticated_with_SECURITYHOTSPOT_ADMIN_permission(@Nullable String permission) {
  306. ProjectData projectData = dbTester.components().insertPublicProject();
  307. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  308. userSessionRule.registerProjects(projectData.getProjectDto())
  309. .addProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN, projectData.getProjectDto());
  310. if (permission != null) {
  311. userSessionRule.addProjectPermission(permission, projectData.getProjectDto());
  312. }
  313. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  314. RuleDto rule = newRule(SECURITY_HOTSPOT);
  315. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
  316. mockChangelogAndCommentsFormattingContext();
  317. Hotspots.ShowWsResponse response = newRequest(hotspot)
  318. .executeProtobuf(Hotspots.ShowWsResponse.class);
  319. assertThat(response.getCanChangeStatus()).isTrue();
  320. }
  321. @DataProvider
  322. public static Object[][] allPublicProjectPermissionsButSECURITYHOTSPOT_ADMIN() {
  323. return new Object[][] {
  324. {null}, // no permission
  325. {UserRole.ADMIN},
  326. {UserRole.SCAN},
  327. {UserRole.ISSUE_ADMIN}
  328. };
  329. }
  330. @Test
  331. @UseDataProvider("allPrivateProjectPermissionsButSECURITYHOTSPOT_ADMIN_and_USER")
  332. public void return_canChangeStatus_false_on_private_project_without_SECURITYHOTSPOT_ADMIN_permission(@Nullable String permission) {
  333. ProjectData projectData = dbTester.components().insertPrivateProject();
  334. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  335. userSessionRule
  336. .registerProjects(projectData.getProjectDto())
  337. .logIn()
  338. .addProjectPermission(UserRole.USER, projectData.getProjectDto());
  339. if (permission != null) {
  340. userSessionRule.addProjectPermission(permission, projectData.getProjectDto());
  341. }
  342. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  343. RuleDto rule = newRule(SECURITY_HOTSPOT);
  344. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
  345. mockChangelogAndCommentsFormattingContext();
  346. Hotspots.ShowWsResponse response = newRequest(hotspot)
  347. .executeProtobuf(Hotspots.ShowWsResponse.class);
  348. assertThat(response.getCanChangeStatus()).isFalse();
  349. }
  350. @Test
  351. @UseDataProvider("allPrivateProjectPermissionsButSECURITYHOTSPOT_ADMIN_and_USER")
  352. public void return_canChangeStatus_false_on_private_project_with_SECURITYHOTSPOT_ADMIN_permission(@Nullable String permission) {
  353. ProjectData projectData = dbTester.components().insertPrivateProject();
  354. ComponentDto mainBranch = projectData.getMainBranchComponent();
  355. userSessionRule
  356. .registerProjects(projectData.getProjectDto())
  357. .logIn()
  358. .addProjectPermission(UserRole.USER, projectData.getProjectDto())
  359. .addProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN, projectData.getProjectDto());
  360. if (permission != null) {
  361. userSessionRule.addProjectPermission(permission, projectData.getProjectDto());
  362. }
  363. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranch));
  364. RuleDto rule = newRule(SECURITY_HOTSPOT);
  365. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranch, file);
  366. mockChangelogAndCommentsFormattingContext();
  367. Hotspots.ShowWsResponse response = newRequest(hotspot)
  368. .executeProtobuf(Hotspots.ShowWsResponse.class);
  369. assertThat(response.getCanChangeStatus()).isTrue();
  370. }
  371. @DataProvider
  372. public static Object[][] allPrivateProjectPermissionsButSECURITYHOTSPOT_ADMIN_and_USER() {
  373. return new Object[][] {
  374. {null}, // only USER permission
  375. {UserRole.CODEVIEWER},
  376. {UserRole.ADMIN},
  377. {UserRole.SCAN},
  378. {UserRole.ISSUE_ADMIN}
  379. };
  380. }
  381. @Test
  382. @UseDataProvider("statusAndResolutionCombinations")
  383. public void returns_status_and_resolution(String status, @Nullable String resolution) {
  384. ProjectData projectData = dbTester.components().insertPrivateProject();
  385. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  386. userSessionRule.registerProjects(projectData.getProjectDto());
  387. userSessionRule.logIn().addProjectPermission(UserRole.USER, projectData.getProjectDto());
  388. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  389. RuleDto rule = newRule(SECURITY_HOTSPOT);
  390. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setStatus(status).setResolution(resolution));
  391. mockChangelogAndCommentsFormattingContext();
  392. Hotspots.ShowWsResponse response = newRequest(hotspot)
  393. .executeProtobuf(Hotspots.ShowWsResponse.class);
  394. assertThat(response.getStatus()).isEqualTo(status);
  395. if (resolution == null) {
  396. assertThat(response.hasResolution()).isFalse();
  397. } else {
  398. assertThat(response.getResolution()).isEqualTo(resolution);
  399. }
  400. }
  401. @DataProvider
  402. public static Object[][] statusAndResolutionCombinations() {
  403. return new Object[][] {
  404. {Issue.STATUS_TO_REVIEW, null},
  405. {Issue.STATUS_REVIEWED, Issue.RESOLUTION_FIXED},
  406. {Issue.STATUS_REVIEWED, Issue.RESOLUTION_SAFE}
  407. };
  408. }
  409. @Test
  410. public void dispatch_description_sections_of_advanced_rule_in_relevant_field() {
  411. ProjectData projectData = dbTester.components().insertPrivateProject();
  412. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  413. userSessionRule.registerProjects(projectData.getProjectDto());
  414. userSessionRule.logIn().addProjectPermission(UserRole.USER, projectData.getProjectDto());
  415. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  416. RuleDescriptionSectionDto introductionSection = generateSectionWithKey(INTRODUCTION_SECTION_KEY);
  417. RuleDescriptionSectionDto rootCauseSection = generateSectionWithKey(ROOT_CAUSE_SECTION_KEY);
  418. RuleDescriptionSectionDto assesTheProblemSection = generateSectionWithKey(ASSESS_THE_PROBLEM_SECTION_KEY);
  419. RuleDescriptionSectionDto resourcesSection = generateSectionWithKey(RESOURCES_SECTION_KEY);
  420. RuleDescriptionSectionDto howToFixSection = generateSectionWithKey(HOW_TO_FIX_SECTION_KEY);
  421. RuleDescriptionSectionDto dummySection = generateSectionWithKey("dummySection");
  422. RuleDto rule = newRuleWithoutSection(SECURITY_HOTSPOT,
  423. r -> r.addRuleDescriptionSectionDto(introductionSection)
  424. .addRuleDescriptionSectionDto(rootCauseSection)
  425. .addRuleDescriptionSectionDto(assesTheProblemSection)
  426. .addRuleDescriptionSectionDto(resourcesSection)
  427. .addRuleDescriptionSectionDto(howToFixSection)
  428. .addRuleDescriptionSectionDto(dummySection)
  429. .setDescriptionFormat(HTML));
  430. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
  431. mockChangelogAndCommentsFormattingContext();
  432. Hotspots.ShowWsResponse response = newRequest(hotspot)
  433. .executeProtobuf(Hotspots.ShowWsResponse.class);
  434. assertThat(response.getRule().getRiskDescription()).isEqualTo(rootCauseSection.getContent());
  435. assertThat(response.getRule().getVulnerabilityDescription()).isEqualTo(assesTheProblemSection.getContent());
  436. assertThat(response.getRule().getFixRecommendations()).isEqualTo(howToFixSection.getContent());
  437. }
  438. @Test
  439. public void fallbacks_to_default_section_in_case_of_legacy_rule() {
  440. ProjectData projectData = dbTester.components().insertPrivateProject();
  441. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  442. userSessionRule.registerProjects(projectData.getProjectDto());
  443. userSessionRule.logIn().addProjectPermission(UserRole.USER, projectData.getProjectDto());
  444. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  445. RuleDescriptionSectionDto introductionSection = generateSectionWithKey(DEFAULT_KEY);
  446. RuleDto rule = newRuleWithoutSection(SECURITY_HOTSPOT,
  447. r -> r.addRuleDescriptionSectionDto(introductionSection)
  448. .setDescriptionFormat(HTML));
  449. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
  450. mockChangelogAndCommentsFormattingContext();
  451. Hotspots.ShowWsResponse response = newRequest(hotspot)
  452. .executeProtobuf(Hotspots.ShowWsResponse.class);
  453. assertThat(response.getRule().getRiskDescription()).isEqualTo(introductionSection.getContent());
  454. assertThat(response.getRule().getVulnerabilityDescription()).isEmpty();
  455. assertThat(response.getRule().getFixRecommendations()).isEmpty();
  456. }
  457. @Test
  458. public void ignore_default_section_if_root_cause_provided() {
  459. ProjectData projectData = dbTester.components().insertPrivateProject();
  460. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  461. userSessionRule.registerProjects(projectData.getProjectDto());
  462. userSessionRule.logIn().addProjectPermission(UserRole.USER, projectData.getProjectDto());
  463. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  464. RuleDescriptionSectionDto introductionSection = generateSectionWithKey(INTRODUCTION_SECTION_KEY);
  465. RuleDescriptionSectionDto rootCauseSection = generateSectionWithKey(ROOT_CAUSE_SECTION_KEY);
  466. RuleDescriptionSectionDto assesTheProblemSection = generateSectionWithKey(ASSESS_THE_PROBLEM_SECTION_KEY);
  467. RuleDto rule = newRuleWithoutSection(SECURITY_HOTSPOT,
  468. r -> r.addRuleDescriptionSectionDto(introductionSection)
  469. .addRuleDescriptionSectionDto(rootCauseSection)
  470. .addRuleDescriptionSectionDto(assesTheProblemSection)
  471. .setDescriptionFormat(HTML));
  472. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
  473. mockChangelogAndCommentsFormattingContext();
  474. Hotspots.ShowWsResponse response = newRequest(hotspot)
  475. .executeProtobuf(Hotspots.ShowWsResponse.class);
  476. assertThat(response.getRule().getRiskDescription()).isEqualTo(rootCauseSection.getContent());
  477. assertThat(response.getRule().getVulnerabilityDescription()).isEqualTo(assesTheProblemSection.getContent());
  478. assertThat(response.getRule().getFixRecommendations()).isEmpty();
  479. }
  480. private RuleDescriptionSectionDto generateSectionWithKey(String assessTheProblemSectionKey) {
  481. return RuleDescriptionSectionDto.builder()
  482. .uuid(uuidFactory.create())
  483. .key(assessTheProblemSectionKey)
  484. .content(randomAlphabetic(200))
  485. .build();
  486. }
  487. @Test
  488. public void returns_html_description_for_custom_rules() {
  489. ProjectData projectData = dbTester.components().insertPrivateProject();
  490. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  491. userSessionRule.registerProjects(projectData.getProjectDto());
  492. userSessionRule.logIn().addProjectPermission(UserRole.USER, projectData.getProjectDto());
  493. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  494. String description = "== Title\n<div>line1\nline2</div>";
  495. RuleDescriptionSectionDto sectionDto = RuleDescriptionSectionDto.builder()
  496. .uuid(uuidFactory.create())
  497. .key(DEFAULT_KEY)
  498. .content(description)
  499. .build();
  500. RuleDto rule = newRuleWithoutSection(SECURITY_HOTSPOT,
  501. r -> r.setTemplateUuid("123")
  502. .addRuleDescriptionSectionDto(sectionDto)
  503. .setDescriptionFormat(MARKDOWN));
  504. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
  505. mockChangelogAndCommentsFormattingContext();
  506. Hotspots.ShowWsResponse response = newRequest(hotspot)
  507. .executeProtobuf(Hotspots.ShowWsResponse.class);
  508. assertThat(response.getRule().getRiskDescription()).isEqualTo("<h2>Title</h2>&lt;div&gt;line1<br/>line2&lt;/div&gt;");
  509. }
  510. @Test
  511. public void handles_null_description_for_custom_rules() {
  512. ProjectData projectData = dbTester.components().insertPrivateProject();
  513. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  514. userSessionRule.registerProjects(projectData.getProjectDto());
  515. userSessionRule.logIn().addProjectPermission(UserRole.USER, projectData.getProjectDto());
  516. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  517. RuleDto rule = newRuleWithoutSection(SECURITY_HOTSPOT, r -> r.setTemplateUuid("123"));
  518. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
  519. mockChangelogAndCommentsFormattingContext();
  520. Hotspots.ShowWsResponse response = newRequest(hotspot)
  521. .executeProtobuf(Hotspots.ShowWsResponse.class);
  522. assertThat(response.getRule().getRiskDescription()).isNullOrEmpty();
  523. }
  524. @Test
  525. public void handle_given_description_section_with_3_contexts_return_one_alphabetically() {
  526. ProjectData projectData = dbTester.components().insertPrivateProject();
  527. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  528. userSessionRule.registerProjects(projectData.getProjectDto());
  529. userSessionRule.logIn().addProjectPermission(UserRole.USER, projectData.getProjectDto());
  530. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  531. RuleDescriptionSectionDto vaadinSection = newContextSpecificDescriptionSection("vaadin");
  532. RuleDescriptionSectionDto gsonSection = newContextSpecificDescriptionSection("gson");
  533. RuleDescriptionSectionDto springSection = newContextSpecificDescriptionSection("spring");
  534. RuleDto rule = newRuleWithoutSection(SECURITY_HOTSPOT,
  535. r -> r.setTemplateUuid("123")
  536. .addRuleDescriptionSectionDto(vaadinSection)
  537. .addRuleDescriptionSectionDto(springSection)
  538. .addRuleDescriptionSectionDto(gsonSection)
  539. .setDescriptionFormat(HTML));
  540. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
  541. mockChangelogAndCommentsFormattingContext();
  542. Hotspots.ShowWsResponse response = newRequest(hotspot)
  543. .executeProtobuf(Hotspots.ShowWsResponse.class);
  544. assertThat(response.getRule().getFixRecommendations()).isEqualTo("gson description");
  545. }
  546. private RuleDescriptionSectionDto newContextSpecificDescriptionSection(String context) {
  547. return RuleDescriptionSectionDto.builder()
  548. .uuid(uuidFactory.create())
  549. .key(HOW_TO_FIX_SECTION_KEY)
  550. .content(context + " description")
  551. .context(RuleDescriptionSectionContextDto.of(context.toLowerCase(), context.toUpperCase()))
  552. .build();
  553. }
  554. @Test
  555. public void returns_hotspot_component_and_rule() {
  556. ProjectData projectData = dbTester.components().insertPublicProject();
  557. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  558. userSessionRule.registerProjects(projectData.getProjectDto());
  559. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  560. RuleDto rule = newRule(SECURITY_HOTSPOT);
  561. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
  562. mockChangelogAndCommentsFormattingContext();
  563. Hotspots.ShowWsResponse response = newRequest(hotspot)
  564. .executeProtobuf(Hotspots.ShowWsResponse.class);
  565. assertThat(response.getKey()).isEqualTo(hotspot.getKey());
  566. verifyComponent(response.getComponent(), file, null, null);
  567. verifyProject(response.getProject(), projectData.getProjectDto(), null, null);
  568. verifyRule(response.getRule(), rule);
  569. assertThat(response.hasTextRange()).isFalse();
  570. }
  571. @Test
  572. public void returns_no_textRange_when_locations_have_none() {
  573. ProjectData projectData = dbTester.components().insertPublicProject();
  574. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  575. userSessionRule.registerProjects(projectData.getProjectDto());
  576. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  577. RuleDto rule = newRule(SECURITY_HOTSPOT);
  578. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file,
  579. t -> t.setLocations(DbIssues.Locations.newBuilder().build()));
  580. mockChangelogAndCommentsFormattingContext();
  581. Hotspots.ShowWsResponse response = newRequest(hotspot)
  582. .executeProtobuf(Hotspots.ShowWsResponse.class);
  583. assertThat(response.hasTextRange()).isFalse();
  584. }
  585. @Test
  586. @UseDataProvider("randomTextRangeValues")
  587. public void returns_textRange(int startLine, int endLine, int startOffset, int endOffset) {
  588. ProjectData projectData = dbTester.components().insertPublicProject();
  589. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  590. userSessionRule.registerProjects(projectData.getProjectDto());
  591. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  592. RuleDto rule = newRule(SECURITY_HOTSPOT);
  593. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file,
  594. t -> t.setLocations(DbIssues.Locations.newBuilder().setTextRange(textRange(startLine, endLine, startOffset, endOffset)).build()));
  595. mockChangelogAndCommentsFormattingContext();
  596. Hotspots.ShowWsResponse response = newRequest(hotspot)
  597. .executeProtobuf(Hotspots.ShowWsResponse.class);
  598. assertThat(response.hasTextRange()).isTrue();
  599. Common.TextRange textRange = response.getTextRange();
  600. assertThat(textRange.getStartLine()).isEqualTo(startLine);
  601. assertThat(textRange.getEndLine()).isEqualTo(endLine);
  602. assertThat(textRange.getStartOffset()).isEqualTo(startOffset);
  603. assertThat(textRange.getEndOffset()).isEqualTo(endOffset);
  604. }
  605. @Test
  606. public void returns_no_assignee_when_user_does_not_exist() {
  607. ProjectData projectData = dbTester.components().insertPublicProject();
  608. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  609. userSessionRule.registerProjects(projectData.getProjectDto());
  610. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  611. RuleDto rule = newRule(SECURITY_HOTSPOT);
  612. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setAssigneeUuid(randomAlphabetic(10)));
  613. mockChangelogAndCommentsFormattingContext();
  614. Hotspots.ShowWsResponse response = newRequest(hotspot)
  615. .executeProtobuf(Hotspots.ShowWsResponse.class);
  616. assertThat(response.hasAssignee()).isFalse();
  617. }
  618. @Test
  619. public void returns_assignee_details_when_user_exists() {
  620. ProjectData projectData = dbTester.components().insertPublicProject();
  621. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  622. userSessionRule.registerProjects(projectData.getProjectDto());
  623. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  624. RuleDto rule = newRule(SECURITY_HOTSPOT);
  625. UserDto assignee = dbTester.users().insertUser();
  626. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setAssigneeUuid(assignee.getUuid()));
  627. mockChangelogAndCommentsFormattingContext();
  628. Hotspots.ShowWsResponse response = newRequest(hotspot)
  629. .executeProtobuf(Hotspots.ShowWsResponse.class);
  630. assertThat(response.getAssignee()).isEqualTo(assignee.getLogin());
  631. assertThat(response.getUsersList()).hasSize(1);
  632. User wsAssignee = response.getUsersList().iterator().next();
  633. assertThat(wsAssignee.getLogin()).isEqualTo(assignee.getLogin());
  634. assertThat(wsAssignee.getName()).isEqualTo(assignee.getName());
  635. assertThat(wsAssignee.getActive()).isEqualTo(assignee.isActive());
  636. assertThat(wsAssignee.getAvatar()).isEqualTo(avatarResolver.create(assignee));
  637. }
  638. @Test
  639. public void returns_no_avatar_if_assignee_has_no_email() {
  640. ProjectData projectData = dbTester.components().insertPublicProject();
  641. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  642. userSessionRule.registerProjects(projectData.getProjectDto());
  643. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  644. RuleDto rule = newRule(SECURITY_HOTSPOT);
  645. UserDto assignee = dbTester.users().insertUser(t -> t.setEmail(null));
  646. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setAssigneeUuid(assignee.getUuid()));
  647. mockChangelogAndCommentsFormattingContext();
  648. Hotspots.ShowWsResponse response = newRequest(hotspot)
  649. .executeProtobuf(Hotspots.ShowWsResponse.class);
  650. assertThat(response.getUsersList()).hasSize(1);
  651. assertThat(response.getUsersList().iterator().next().hasAvatar()).isFalse();
  652. }
  653. @Test
  654. public void returns_inactive_when_assignee_is_inactive() {
  655. ProjectData projectData = dbTester.components().insertPublicProject();
  656. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  657. userSessionRule.registerProjects(projectData.getProjectDto());
  658. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  659. RuleDto rule = newRule(SECURITY_HOTSPOT);
  660. UserDto assignee = dbTester.users().insertUser(t -> t.setActive(false));
  661. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setAssigneeUuid(assignee.getUuid()));
  662. mockChangelogAndCommentsFormattingContext();
  663. Hotspots.ShowWsResponse response = newRequest(hotspot)
  664. .executeProtobuf(Hotspots.ShowWsResponse.class);
  665. assertThat(response.getUsersList()).hasSize(1);
  666. assertThat(response.getUsersList().iterator().next().getActive()).isFalse();
  667. }
  668. @Test
  669. public void returns_author_login_when_user_does_not_exist() {
  670. ProjectData projectData = dbTester.components().insertPublicProject();
  671. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  672. userSessionRule.registerProjects(projectData.getProjectDto());
  673. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  674. RuleDto rule = newRule(SECURITY_HOTSPOT);
  675. String authorLogin = randomAlphabetic(10);
  676. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setAuthorLogin(authorLogin));
  677. mockChangelogAndCommentsFormattingContext();
  678. Hotspots.ShowWsResponse response = newRequest(hotspot)
  679. .executeProtobuf(Hotspots.ShowWsResponse.class);
  680. assertThat(response.getUsersList()).isEmpty();
  681. assertThat(response.getAuthor()).isEqualTo(authorLogin);
  682. }
  683. @Test
  684. public void returns_author_details_when_user_exists() {
  685. ProjectData projectData = dbTester.components().insertPublicProject();
  686. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  687. userSessionRule.registerProjects(projectData.getProjectDto());
  688. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  689. RuleDto rule = newRule(SECURITY_HOTSPOT);
  690. UserDto author = dbTester.users().insertUser();
  691. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setAuthorLogin(author.getLogin()));
  692. mockChangelogAndCommentsFormattingContext();
  693. Hotspots.ShowWsResponse response = newRequest(hotspot)
  694. .executeProtobuf(Hotspots.ShowWsResponse.class);
  695. assertThat(response.getAuthor()).isEqualTo(author.getLogin());
  696. User wsAuthorFromList = response.getUsersList().iterator().next();
  697. assertThat(wsAuthorFromList.getLogin()).isEqualTo(author.getLogin());
  698. assertThat(wsAuthorFromList.getName()).isEqualTo(author.getName());
  699. assertThat(wsAuthorFromList.getActive()).isEqualTo(author.isActive());
  700. assertThat(wsAuthorFromList.getAvatar()).isEqualTo(avatarResolver.create(author));
  701. }
  702. @Test
  703. public void returns_no_avatar_if_author_has_no_email() {
  704. ProjectData projectData = dbTester.components().insertPublicProject();
  705. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  706. userSessionRule.registerProjects(projectData.getProjectDto());
  707. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  708. RuleDto rule = newRule(SECURITY_HOTSPOT);
  709. UserDto author = dbTester.users().insertUser(t -> t.setEmail(null));
  710. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setAuthorLogin(author.getLogin()));
  711. mockChangelogAndCommentsFormattingContext();
  712. Hotspots.ShowWsResponse response = newRequest(hotspot)
  713. .executeProtobuf(Hotspots.ShowWsResponse.class);
  714. assertThat(response.getUsersList()).hasSize(1);
  715. assertThat(response.getUsersList().iterator().next().hasAvatar()).isFalse();
  716. }
  717. @Test
  718. public void returns_inactive_if_author_is_inactive() {
  719. ProjectData projectData = dbTester.components().insertPublicProject();
  720. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  721. userSessionRule.registerProjects(projectData.getProjectDto());
  722. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  723. RuleDto rule = newRule(SECURITY_HOTSPOT);
  724. UserDto author = dbTester.users().insertUser(t -> t.setActive(false));
  725. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setAuthorLogin(author.getLogin()));
  726. mockChangelogAndCommentsFormattingContext();
  727. Hotspots.ShowWsResponse response = newRequest(hotspot)
  728. .executeProtobuf(Hotspots.ShowWsResponse.class);
  729. assertThat(response.getUsersList()).hasSize(1);
  730. assertThat(response.getUsersList().iterator().next().getActive()).isFalse();
  731. }
  732. @DataProvider
  733. public static Object[][] randomTextRangeValues() {
  734. int startLine = RANDOM.nextInt(200);
  735. int endLine = RANDOM.nextInt(200);
  736. int startOffset = RANDOM.nextInt(200);
  737. int endOffset = RANDOM.nextInt(200);
  738. return new Object[][] {
  739. {startLine, endLine, startOffset, endOffset}
  740. };
  741. }
  742. @Test
  743. public void returns_textRange_missing_fields() {
  744. ProjectData projectData = dbTester.components().insertPublicProject();
  745. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  746. userSessionRule.registerProjects(projectData.getProjectDto());
  747. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  748. RuleDto rule = newRule(SECURITY_HOTSPOT);
  749. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file,
  750. t -> t.setLocations(DbIssues.Locations.newBuilder()
  751. .setTextRange(TextRange.newBuilder().build())
  752. .build()));
  753. mockChangelogAndCommentsFormattingContext();
  754. Hotspots.ShowWsResponse response = newRequest(hotspot)
  755. .executeProtobuf(Hotspots.ShowWsResponse.class);
  756. assertThat(response.hasTextRange()).isTrue();
  757. Common.TextRange textRange = response.getTextRange();
  758. assertThat(textRange.hasStartLine()).isFalse();
  759. assertThat(textRange.hasEndLine()).isFalse();
  760. assertThat(textRange.hasStartOffset()).isFalse();
  761. assertThat(textRange.hasEndOffset()).isFalse();
  762. }
  763. @Test
  764. @UseDataProvider("allSQCategoryAndVulnerabilityProbability")
  765. public void returns_securityCategory_and_vulnerabilityProbability_of_rule(Set<String> standards,
  766. SQCategory expected) {
  767. ProjectData projectData = dbTester.components().insertPublicProject();
  768. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  769. userSessionRule.registerProjects(projectData.getProjectDto());
  770. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  771. RuleDto rule = newRule(SECURITY_HOTSPOT, t -> t.setSecurityStandards(standards));
  772. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file,
  773. t -> t.setLocations(DbIssues.Locations.newBuilder()
  774. .setTextRange(TextRange.newBuilder().build())
  775. .build()));
  776. mockChangelogAndCommentsFormattingContext();
  777. Hotspots.ShowWsResponse response = newRequest(hotspot)
  778. .executeProtobuf(Hotspots.ShowWsResponse.class);
  779. Hotspots.Rule wsRule = response.getRule();
  780. assertThat(wsRule.getSecurityCategory()).isEqualTo(expected.getKey());
  781. assertThat(wsRule.getVulnerabilityProbability()).isEqualTo(expected.getVulnerability().name());
  782. }
  783. @DataProvider
  784. public static Object[][] allSQCategoryAndVulnerabilityProbability() {
  785. Stream<Object[]> allButOthers = SecurityStandards.CWES_BY_SQ_CATEGORY
  786. .entrySet()
  787. .stream()
  788. .map(t -> new Object[] {
  789. t.getValue().stream().map(s -> "cwe:" + s).collect(Collectors.toSet()),
  790. t.getKey()
  791. });
  792. Stream<Object[]> others = Stream.of(
  793. new Object[] {emptySet(), SQCategory.OTHERS},
  794. new Object[] {ImmutableSet.of("foo", "bar", "acme"), SQCategory.OTHERS});
  795. return Stream.concat(allButOthers, others)
  796. .toArray(Object[][]::new);
  797. }
  798. @Test
  799. public void returns_project_twice_when_hotspot_on_project() {
  800. ProjectData projectData = dbTester.components().insertPublicProject();
  801. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  802. userSessionRule.registerProjects(projectData.getProjectDto());
  803. RuleDto rule = newRule(SECURITY_HOTSPOT);
  804. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, mainBranchComponent,
  805. t -> t.setLocations(DbIssues.Locations.newBuilder()
  806. .setTextRange(TextRange.newBuilder().build())
  807. .build()));
  808. mockChangelogAndCommentsFormattingContext();
  809. Hotspots.ShowWsResponse response = newRequest(hotspot)
  810. .executeProtobuf(Hotspots.ShowWsResponse.class);
  811. verifyProject(response.getProject(), projectData.getProjectDto(), null, null);
  812. verifyComponent(response.getComponent(), mainBranchComponent, null, null);
  813. }
  814. @Test
  815. public void returns_branch_but_no_pullRequest_on_component_and_project_on_non_main_branch() {
  816. ProjectData projectData = dbTester.components().insertPublicProject();
  817. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  818. String branchName = randomAlphanumeric(248);
  819. ComponentDto branch = dbTester.components().insertProjectBranch(mainBranchComponent, b -> b.setKey(branchName));
  820. userSessionRule.addProjectBranchMapping(mainBranchComponent.uuid(), branch);
  821. ComponentDto file = dbTester.components().insertComponent(newFileDto(branch, mainBranchComponent.uuid()));
  822. userSessionRule.registerProjects(projectData.getProjectDto());
  823. RuleDto rule = newRule(SECURITY_HOTSPOT);
  824. IssueDto hotspot = dbTester.issues().insertHotspot(rule, branch, file,
  825. t -> t.setLocations(DbIssues.Locations.newBuilder()
  826. .setTextRange(TextRange.newBuilder().build())
  827. .build()));
  828. mockChangelogAndCommentsFormattingContext();
  829. Hotspots.ShowWsResponse response = newRequest(hotspot)
  830. .executeProtobuf(Hotspots.ShowWsResponse.class);
  831. verifyProject(response.getProject(), projectData.getProjectDto(), branchName, null);
  832. verifyComponent(response.getComponent(), file, branchName, null);
  833. }
  834. @Test
  835. public void returns_pullRequest_but_no_branch_on_component_and_project_on_pullRequest() {
  836. ProjectData projectData = dbTester.components().insertPublicProject();
  837. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  838. String pullRequestKey = randomAlphanumeric(100);
  839. ComponentDto pullRequest = dbTester.components().insertProjectBranch(mainBranchComponent,
  840. t -> t.setBranchType(BranchType.PULL_REQUEST).setKey(pullRequestKey));
  841. userSessionRule.addProjectBranchMapping(mainBranchComponent.uuid(), pullRequest);
  842. ComponentDto file = dbTester.components().insertComponent(newFileDto(pullRequest));
  843. userSessionRule.registerProjects(projectData.getProjectDto());
  844. RuleDto rule = newRule(SECURITY_HOTSPOT);
  845. IssueDto hotspot = dbTester.issues().insertHotspot(rule, pullRequest, file,
  846. t -> t.setLocations(DbIssues.Locations.newBuilder()
  847. .setTextRange(TextRange.newBuilder().build())
  848. .build()));
  849. mockChangelogAndCommentsFormattingContext();
  850. Hotspots.ShowWsResponse response = newRequest(hotspot)
  851. .executeProtobuf(Hotspots.ShowWsResponse.class);
  852. verifyProject(response.getProject(), projectData.getProjectDto(), null, pullRequestKey);
  853. verifyComponent(response.getComponent(), file, null, pullRequestKey);
  854. }
  855. @Test
  856. public void returns_hotspot_changelog_and_comments() {
  857. ProjectData projectData = dbTester.components().insertPublicProject();
  858. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  859. userSessionRule.registerProjects(projectData.getProjectDto());
  860. RuleDto rule = newRule(SECURITY_HOTSPOT);
  861. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  862. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file,
  863. t -> t.setLocations(DbIssues.Locations.newBuilder()
  864. .setTextRange(TextRange.newBuilder().build())
  865. .build()));
  866. List<Common.Changelog> changelog = IntStream.range(0, 1 + new Random().nextInt(12))
  867. .mapToObj(i -> Common.Changelog.newBuilder().setUser("u" + i).build())
  868. .toList();
  869. List<Common.Comment> comments = IntStream.range(0, 1 + new Random().nextInt(12))
  870. .mapToObj(i -> Common.Comment.newBuilder().setKey("u" + i).build())
  871. .toList();
  872. FormattingContext formattingContext = mockChangelogAndCommentsFormattingContext();
  873. when(issueChangeSupport.formatChangelog(any(), any())).thenReturn(changelog.stream());
  874. when(issueChangeSupport.formatComments(any(), any(), any())).thenReturn(comments.stream());
  875. Hotspots.ShowWsResponse response = newRequest(hotspot)
  876. .executeProtobuf(Hotspots.ShowWsResponse.class);
  877. assertThat(response.getChangelogList())
  878. .extracting(Common.Changelog::getUser)
  879. .containsExactly(changelog.stream().map(Common.Changelog::getUser).toArray(String[]::new));
  880. assertThat(response.getCommentList())
  881. .extracting(Common.Comment::getKey)
  882. .containsExactly(comments.stream().map(Common.Comment::getKey).toArray(String[]::new));
  883. verify(issueChangeSupport).newFormattingContext(any(DbSession.class), argThat(new IssueDtoSetArgumentMatcher(hotspot)), eq(Load.ALL), eq(emptySet()), eq(Set.of(file)));
  884. verify(issueChangeSupport).formatChangelog(argThat(new IssueDtoArgumentMatcher(hotspot)), eq(formattingContext));
  885. verify(issueChangeSupport).formatComments(argThat(new IssueDtoArgumentMatcher(hotspot)), any(Common.Comment.Builder.class), eq(formattingContext));
  886. }
  887. @Test
  888. public void returns_user_details_of_users_from_ChangelogAndComments() {
  889. ProjectData projectData = dbTester.components().insertPublicProject();
  890. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  891. userSessionRule.registerProjects(projectData.getProjectDto());
  892. RuleDto rule = newRule(SECURITY_HOTSPOT);
  893. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  894. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
  895. FormattingContext formattingContext = mockChangelogAndCommentsFormattingContext();
  896. Set<UserDto> changeLogAndCommentsUsers = IntStream.range(0, 1 + RANDOM.nextInt(14))
  897. .mapToObj(i -> UserTesting.newUserDto())
  898. .collect(Collectors.toSet());
  899. when(formattingContext.getUsers()).thenReturn(changeLogAndCommentsUsers);
  900. Hotspots.ShowWsResponse response = newRequest(hotspot)
  901. .executeProtobuf(Hotspots.ShowWsResponse.class);
  902. assertThat(response.getUsersList())
  903. .extracting(User::getLogin, User::getName, User::getActive)
  904. .containsExactlyInAnyOrder(
  905. changeLogAndCommentsUsers.stream()
  906. .map(t -> tuple(t.getLogin(), t.getName(), t.isActive()))
  907. .toArray(Tuple[]::new));
  908. }
  909. @Test
  910. public void returns_user_of_users_from_ChangelogAndComments_and_assignee_and_author() {
  911. ProjectData projectData = dbTester.components().insertPublicProject();
  912. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  913. userSessionRule.registerProjects(projectData.getProjectDto());
  914. RuleDto rule = newRule(SECURITY_HOTSPOT);
  915. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  916. UserDto author = dbTester.users().insertUser();
  917. UserDto assignee = dbTester.users().insertUser();
  918. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file,
  919. t -> t.setAuthorLogin(author.getLogin())
  920. .setAssigneeUuid(assignee.getUuid()));
  921. FormattingContext formattingContext = mockChangelogAndCommentsFormattingContext();
  922. Set<UserDto> changeLogAndCommentsUsers = IntStream.range(0, 1 + RANDOM.nextInt(14))
  923. .mapToObj(i -> UserTesting.newUserDto())
  924. .collect(Collectors.toSet());
  925. when(formattingContext.getUsers()).thenReturn(changeLogAndCommentsUsers);
  926. Hotspots.ShowWsResponse response = newRequest(hotspot)
  927. .executeProtobuf(Hotspots.ShowWsResponse.class);
  928. assertThat(response.getUsersList())
  929. .extracting(User::getLogin, User::getName, User::getActive)
  930. .containsExactlyInAnyOrder(
  931. Stream.concat(
  932. Stream.of(author, assignee),
  933. changeLogAndCommentsUsers.stream())
  934. .map(t -> tuple(t.getLogin(), t.getName(), t.isActive()))
  935. .toArray(Tuple[]::new));
  936. }
  937. @Test
  938. public void do_not_duplicate_user_if_author_assignee_ChangeLogComment_user() {
  939. ProjectData projectData = dbTester.components().insertPublicProject();
  940. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  941. userSessionRule.registerProjects(projectData.getProjectDto());
  942. RuleDto rule = newRule(SECURITY_HOTSPOT);
  943. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  944. UserDto author = dbTester.users().insertUser();
  945. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file,
  946. t -> t.setAuthorLogin(author.getLogin())
  947. .setAssigneeUuid(author.getUuid()));
  948. FormattingContext formattingContext = mockChangelogAndCommentsFormattingContext();
  949. when(formattingContext.getUsers()).thenReturn(ImmutableSet.of(author));
  950. Hotspots.ShowWsResponse response = newRequest(hotspot)
  951. .executeProtobuf(Hotspots.ShowWsResponse.class);
  952. assertThat(response.getUsersList())
  953. .extracting(User::getLogin, User::getName, User::getActive)
  954. .containsOnly(tuple(author.getLogin(), author.getName(), author.isActive()));
  955. }
  956. @Test
  957. public void response_shouldContainCodeVariants() {
  958. ProjectData projectData = dbTester.components().insertPublicProject();
  959. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  960. userSessionRule.registerProjects(projectData.getProjectDto());
  961. ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
  962. RuleDto rule = newRule(SECURITY_HOTSPOT);
  963. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setCodeVariants(List.of("variant1", "variant2")));
  964. mockChangelogAndCommentsFormattingContext();
  965. Hotspots.ShowWsResponse response = newRequest(hotspot)
  966. .executeProtobuf(Hotspots.ShowWsResponse.class);
  967. assertThat(response.getCodeVariantsList()).containsOnly("variant1", "variant2");
  968. }
  969. @Test
  970. public void verify_response_example() {
  971. ProjectData projectData = dbTester.components().insertPublicProject(componentDto -> componentDto
  972. .setName("test-project")
  973. .setLongName("test-project")
  974. .setKey("com.sonarsource:test-project"));
  975. ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
  976. userSessionRule.registerProjects(projectData.getProjectDto())
  977. .addProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN, projectData.getProjectDto());
  978. ComponentDto file = dbTester.components().insertComponent(
  979. newFileDto(mainBranchComponent)
  980. .setKey("com.sonarsource:test-project:src/main/java/com/sonarsource/FourthClass.java")
  981. .setName("FourthClass.java")
  982. .setLongName("src/main/java/com/sonarsource/FourthClass.java")
  983. .setPath("src/main/java/com/sonarsource/FourthClass.java"));
  984. UserDto author = dbTester.users().insertUser(u -> u.setLogin("joe")
  985. .setName("Joe"));
  986. long time = 1577976190000L;
  987. RuleDto rule = newRule(SECURITY_HOTSPOT, r -> r.setRuleKey("S4787")
  988. .setRepositoryKey("java")
  989. .setName("rule-name")
  990. .setSecurityStandards(Sets.newHashSet(SQCategory.WEAK_CRYPTOGRAPHY.getKey())));
  991. IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, h -> h
  992. .setAssigneeUuid("assignee-uuid")
  993. .setAuthorLogin("joe")
  994. .setMessage("message")
  995. .setMessageFormattings(DbIssues.MessageFormattings.newBuilder().addMessageFormatting(MESSAGE_FORMATTING).build())
  996. .setLine(10)
  997. .setChecksum("a227e508d6646b55a086ee11d63b21e9")
  998. .setIssueCreationTime(time)
  999. .setIssueUpdateTime(time)
  1000. .setAuthorLogin(author.getLogin())
  1001. .setAssigneeUuid(author.getUuid())
  1002. .setKee("AW9mgJw6eFC3pGl94Wrf")
  1003. .setCodeVariants(List.of("windows", "linux")));
  1004. List<Common.Changelog> changelog = IntStream.range(0, 3)
  1005. .mapToObj(i -> Common.Changelog.newBuilder()
  1006. .setUser("joe")
  1007. .setCreationDate("2020-01-02T14:44:55+0100")
  1008. .addDiffs(Diff.newBuilder().setKey("diff-key-" + i).setNewValue("new-value-" + i).setOldValue("old-value-" + i))
  1009. .setIsUserActive(true)
  1010. .setUserName("Joe")
  1011. .setAvatar("my-avatar")
  1012. .build())
  1013. .toList();
  1014. List<Common.Comment> comments = IntStream.range(0, 3)
  1015. .mapToObj(i -> Common.Comment.newBuilder()
  1016. .setKey("comment-" + i)
  1017. .setHtmlText("html text " + i)
  1018. .setLogin("Joe")
  1019. .setMarkdown("markdown " + i)
  1020. .setCreatedAt("2020-01-02T14:47:47+0100")
  1021. .build())
  1022. .toList();
  1023. mockChangelogAndCommentsFormattingContext();
  1024. when(issueChangeSupport.formatChangelog(any(), any())).thenReturn(changelog.stream());
  1025. when(issueChangeSupport.formatComments(any(), any(), any())).thenReturn(comments.stream());
  1026. assertThat(actionTester.getDef().responseExampleAsString()).isNotNull();
  1027. newRequest(hotspot)
  1028. .execute()
  1029. .assertJson(actionTester.getDef().responseExampleAsString());
  1030. }
  1031. private FormattingContext mockChangelogAndCommentsFormattingContext() {
  1032. FormattingContext formattingContext = Mockito.mock(FormattingContext.class);
  1033. when(issueChangeSupport.newFormattingContext(any(), any(), any(), anySet(), anySet())).thenReturn(formattingContext);
  1034. return formattingContext;
  1035. }
  1036. private void verifyRule(Hotspots.Rule wsRule, RuleDto dto) {
  1037. assertThat(wsRule.getKey()).isEqualTo(dto.getKey().toString());
  1038. assertThat(wsRule.getName()).isEqualTo(dto.getName());
  1039. assertThat(wsRule.getSecurityCategory()).isEqualTo(SQCategory.OTHERS.getKey());
  1040. assertThat(wsRule.getVulnerabilityProbability()).isEqualTo(SQCategory.OTHERS.getVulnerability().name());
  1041. }
  1042. private static void verifyComponent(Hotspots.Component wsComponent, ComponentDto dto, @Nullable String branch, @Nullable String pullRequest) {
  1043. assertThat(wsComponent.getKey()).isEqualTo(dto.getKey());
  1044. if (dto.path() == null) {
  1045. assertThat(wsComponent.hasPath()).isFalse();
  1046. } else {
  1047. assertThat(wsComponent.getPath()).isEqualTo(dto.path());
  1048. }
  1049. assertThat(wsComponent.getQualifier()).isEqualTo(dto.qualifier());
  1050. assertThat(wsComponent.getName()).isEqualTo(dto.name());
  1051. assertThat(wsComponent.getLongName()).isEqualTo(dto.longName());
  1052. if (branch == null) {
  1053. assertThat(wsComponent.hasBranch()).isFalse();
  1054. } else {
  1055. assertThat(wsComponent.getBranch()).isEqualTo(branch);
  1056. }
  1057. if (pullRequest == null) {
  1058. assertThat(wsComponent.hasPullRequest()).isFalse();
  1059. } else {
  1060. assertThat(wsComponent.getPullRequest()).isEqualTo(pullRequest);
  1061. }
  1062. }
  1063. private static void verifyProject(Hotspots.Component wsComponent, ProjectDto dto, @Nullable String branch, @Nullable String pullRequest) {
  1064. assertThat(wsComponent.getKey()).isEqualTo(dto.getKey());
  1065. assertThat(wsComponent.hasPath()).isFalse();
  1066. assertThat(wsComponent.getQualifier()).isEqualTo(dto.getQualifier());
  1067. assertThat(wsComponent.getName()).isEqualTo(dto.getName());
  1068. assertThat(wsComponent.getLongName()).isEqualTo(dto.getName());
  1069. if (branch == null) {
  1070. assertThat(wsComponent.hasBranch()).isFalse();
  1071. } else {
  1072. assertThat(wsComponent.getBranch()).isEqualTo(branch);
  1073. }
  1074. if (pullRequest == null) {
  1075. assertThat(wsComponent.hasPullRequest()).isFalse();
  1076. } else {
  1077. assertThat(wsComponent.getPullRequest()).isEqualTo(pullRequest);
  1078. }
  1079. }
  1080. private static TextRange textRange(int startLine, int endLine, int startOffset, int endOffset) {
  1081. return TextRange.newBuilder()
  1082. .setStartLine(startLine)
  1083. .setEndLine(endLine)
  1084. .setStartOffset(startOffset)
  1085. .setEndOffset(endOffset)
  1086. .build();
  1087. }
  1088. private TestRequest newRequest(IssueDto hotspot) {
  1089. return actionTester.newRequest()
  1090. .setParam("hotspot", hotspot.getKey());
  1091. }
  1092. private RuleDto newRule(RuleType ruleType) {
  1093. return newRule(ruleType, t -> {
  1094. });
  1095. }
  1096. private RuleDto newRule(RuleType ruleType, Consumer<RuleDto> populate) {
  1097. return newRule(ruleType, RuleTesting::newRule, populate);
  1098. }
  1099. private RuleDto newRuleWithoutSection(RuleType ruleType, Consumer<RuleDto> populate) {
  1100. return newRule(ruleType, RuleTesting::newRuleWithoutDescriptionSection, populate);
  1101. }
  1102. private RuleDto newRule(RuleType ruleType, Supplier<RuleDto> ruleDefinitionDtoSupplier, Consumer<RuleDto> populate) {
  1103. RuleDto ruleDefinitionDto = ruleDefinitionDtoSupplier.get().setType(ruleType);
  1104. populate.accept(ruleDefinitionDto);
  1105. dbTester.rules().insert(ruleDefinitionDto);
  1106. return ruleDefinitionDto;
  1107. }
  1108. private static class IssueDtoSetArgumentMatcher implements ArgumentMatcher<Set<IssueDto>> {
  1109. private final IssueDto expected;
  1110. private IssueDtoSetArgumentMatcher(IssueDto expected) {
  1111. this.expected = expected;
  1112. }
  1113. @Override
  1114. public boolean matches(Set<IssueDto> argument) {
  1115. return argument != null && argument.size() == 1 && argument.iterator().next().getKey().equals(expected.getKey());
  1116. }
  1117. @Override
  1118. public String toString() {
  1119. return "Set<IssueDto>[" + expected.getKey() + "]";
  1120. }
  1121. }
  1122. private static class IssueDtoArgumentMatcher implements ArgumentMatcher<IssueDto> {
  1123. private final IssueDto expected;
  1124. private IssueDtoArgumentMatcher(IssueDto expected) {
  1125. this.expected = expected;
  1126. }
  1127. @Override
  1128. public boolean matches(IssueDto argument) {
  1129. return argument != null && argument.getKey().equals(expected.getKey());
  1130. }
  1131. @Override
  1132. public String toString() {
  1133. return "IssueDto[key=" + expected.getKey() + "]";
  1134. }
  1135. }
  1136. }