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.

SearchActionTest.java 46KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2020 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.server.issue.ws;
  21. import com.google.common.collect.Sets;
  22. import com.google.gson.JsonElement;
  23. import com.google.gson.JsonParser;
  24. import java.time.Clock;
  25. import java.util.Arrays;
  26. import java.util.Collections;
  27. import java.util.List;
  28. import java.util.Random;
  29. import java.util.function.Consumer;
  30. import java.util.stream.Collectors;
  31. import java.util.stream.IntStream;
  32. import java.util.stream.Stream;
  33. import org.junit.Before;
  34. import org.junit.Rule;
  35. import org.junit.Test;
  36. import org.junit.rules.ExpectedException;
  37. import org.sonar.api.resources.Languages;
  38. import org.sonar.api.rule.RuleStatus;
  39. import org.sonar.api.rules.RuleType;
  40. import org.sonar.api.server.ws.WebService;
  41. import org.sonar.api.utils.Durations;
  42. import org.sonar.api.utils.System2;
  43. import org.sonar.db.DbClient;
  44. import org.sonar.db.DbSession;
  45. import org.sonar.db.DbTester;
  46. import org.sonar.db.component.ComponentDto;
  47. import org.sonar.db.component.ComponentTesting;
  48. import org.sonar.db.issue.IssueChangeDto;
  49. import org.sonar.db.issue.IssueDto;
  50. import org.sonar.db.organization.OrganizationDto;
  51. import org.sonar.db.permission.GroupPermissionDto;
  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.RuleDto;
  56. import org.sonar.db.rule.RuleTesting;
  57. import org.sonar.db.user.UserDto;
  58. import org.sonar.server.es.EsTester;
  59. import org.sonar.server.es.SearchOptions;
  60. import org.sonar.server.es.StartupIndexer;
  61. import org.sonar.server.issue.AvatarResolverImpl;
  62. import org.sonar.server.issue.IssueFieldsSetter;
  63. import org.sonar.server.issue.TextRangeResponseFormatter;
  64. import org.sonar.server.issue.TransitionService;
  65. import org.sonar.server.issue.index.IssueIndex;
  66. import org.sonar.server.issue.index.IssueIndexer;
  67. import org.sonar.server.issue.index.IssueIteratorFactory;
  68. import org.sonar.server.issue.index.IssueQuery;
  69. import org.sonar.server.issue.index.IssueQueryFactory;
  70. import org.sonar.server.issue.workflow.FunctionExecutor;
  71. import org.sonar.server.issue.workflow.IssueWorkflow;
  72. import org.sonar.server.permission.index.PermissionIndexer;
  73. import org.sonar.server.permission.index.WebAuthorizationTypeSupport;
  74. import org.sonar.server.tester.UserSessionRule;
  75. import org.sonar.server.ws.TestResponse;
  76. import org.sonar.server.ws.WsActionTester;
  77. import org.sonarqube.ws.Common;
  78. import org.sonarqube.ws.Common.Severity;
  79. import org.sonarqube.ws.Issues.Issue;
  80. import org.sonarqube.ws.Issues.SearchWsResponse;
  81. import static java.util.Arrays.asList;
  82. import static java.util.Collections.singletonList;
  83. import static org.assertj.core.api.Assertions.assertThat;
  84. import static org.assertj.core.api.Assertions.assertThatThrownBy;
  85. import static org.assertj.core.groups.Tuple.tuple;
  86. import static org.junit.rules.ExpectedException.none;
  87. import static org.sonar.api.issue.Issue.RESOLUTION_FIXED;
  88. import static org.sonar.api.issue.Issue.STATUS_RESOLVED;
  89. import static org.sonar.api.rules.RuleType.CODE_SMELL;
  90. import static org.sonar.api.server.ws.WebService.Param.FACETS;
  91. import static org.sonar.api.utils.DateUtils.formatDateTime;
  92. import static org.sonar.api.utils.DateUtils.parseDate;
  93. import static org.sonar.api.utils.DateUtils.parseDateTime;
  94. import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
  95. import static org.sonar.db.component.ComponentTesting.newFileDto;
  96. import static org.sonar.db.issue.IssueTesting.newDto;
  97. import static org.sonar.server.tester.UserSessionRule.standalone;
  98. import static org.sonarqube.ws.Common.RuleType.BUG;
  99. import static org.sonarqube.ws.Common.RuleType.VULNERABILITY;
  100. import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BRANCH;
  101. import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ADDITIONAL_FIELDS;
  102. import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ASSIGNEES;
  103. import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS;
  104. import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_AFTER;
  105. import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_HIDE_COMMENTS;
  106. import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RULES;
  107. public class SearchActionTest {
  108. @Rule
  109. public UserSessionRule userSession = standalone();
  110. @Rule
  111. public DbTester db = DbTester.create();
  112. @Rule
  113. public EsTester es = EsTester.create();
  114. @Rule
  115. public ExpectedException expectedException = none();
  116. private DbClient dbClient = db.getDbClient();
  117. private DbSession session = db.getSession();
  118. private IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession, new WebAuthorizationTypeSupport(userSession));
  119. private IssueIndexer issueIndexer = new IssueIndexer(es.client(), dbClient, new IssueIteratorFactory(dbClient));
  120. private IssueQueryFactory issueQueryFactory = new IssueQueryFactory(dbClient, Clock.systemUTC(), userSession);
  121. private IssueFieldsSetter issueFieldsSetter = new IssueFieldsSetter();
  122. private IssueWorkflow issueWorkflow = new IssueWorkflow(new FunctionExecutor(issueFieldsSetter), issueFieldsSetter);
  123. private SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSession, dbClient, new TransitionService(userSession, issueWorkflow));
  124. private Languages languages = new Languages();
  125. private UserResponseFormatter userFormatter = new UserResponseFormatter(new AvatarResolverImpl());
  126. private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new TextRangeResponseFormatter(), userFormatter);
  127. private WsActionTester ws = new WsActionTester(
  128. new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat, System2.INSTANCE, dbClient));
  129. private StartupIndexer permissionIndexer = new PermissionIndexer(dbClient, es.client(), issueIndexer);
  130. @Before
  131. public void setUp() {
  132. issueWorkflow.start();
  133. }
  134. @Test
  135. public void response_contains_all_fields_except_additional_fields() {
  136. OrganizationDto organization = db.organizations().insert();
  137. UserDto user = db.users().insertUser();
  138. db.organizations().addMember(organization, user);
  139. userSession.logIn(user);
  140. ComponentDto project = db.components().insertPublicProject(organization);
  141. indexPermissions();
  142. ComponentDto file = db.components().insertComponent(newFileDto(project));
  143. UserDto simon = db.users().insertUser();
  144. RuleDefinitionDto rule = newRule().getDefinition();
  145. IssueDto issue = db.issues().insertIssue(rule, project, file, i -> i
  146. .setEffort(10L)
  147. .setLine(42)
  148. .setChecksum("a227e508d6646b55a086ee11d63b21e9")
  149. .setMessage("the message")
  150. .setStatus(STATUS_RESOLVED)
  151. .setResolution(RESOLUTION_FIXED)
  152. .setSeverity("MAJOR")
  153. .setType(CODE_SMELL)
  154. .setAuthorLogin("John")
  155. .setAssigneeUuid(simon.getUuid())
  156. .setTags(asList("bug", "owasp"))
  157. .setIssueCreationDate(parseDate("2014-09-03"))
  158. .setIssueUpdateDate(parseDate("2017-12-04")));
  159. indexIssues();
  160. SearchWsResponse response = ws.newRequest()
  161. .executeProtobuf(SearchWsResponse.class);
  162. assertThat(response.getIssuesList())
  163. .extracting(
  164. Issue::getOrganization, Issue::getKey, Issue::getRule, Issue::getSeverity, Issue::getComponent, Issue::getResolution, Issue::getStatus, Issue::getMessage, Issue::getEffort,
  165. Issue::getAssignee, Issue::getAuthor, Issue::getLine, Issue::getHash, Issue::getTagsList, Issue::getCreationDate, Issue::getUpdateDate)
  166. .containsExactlyInAnyOrder(
  167. tuple(organization.getKey(), issue.getKey(), rule.getKey().toString(), Severity.MAJOR, file.getKey(), RESOLUTION_FIXED, STATUS_RESOLVED, "the message", "10min",
  168. simon.getLogin(), "John", 42, "a227e508d6646b55a086ee11d63b21e9", asList("bug", "owasp"), formatDateTime(issue.getIssueCreationDate()),
  169. formatDateTime(issue.getIssueUpdateDate())));
  170. }
  171. @Test
  172. public void issue_on_external_rule() {
  173. OrganizationDto organization = db.organizations().insert();
  174. ComponentDto project = db.components().insertPublicProject(organization);
  175. indexPermissions();
  176. ComponentDto file = db.components().insertComponent(newFileDto(project));
  177. RuleDefinitionDto rule = db.rules().insertIssueRule(RuleTesting.EXTERNAL_XOO, r -> r.setIsExternal(true).setLanguage("xoo"));
  178. IssueDto issue = db.issues().insertIssue(rule, project, file);
  179. indexIssues();
  180. SearchWsResponse response = ws.newRequest()
  181. .executeProtobuf(SearchWsResponse.class);
  182. assertThat(response.getIssuesList())
  183. .extracting(Issue::getKey, Issue::getRule, Issue::getExternalRuleEngine)
  184. .containsExactlyInAnyOrder(tuple(issue.getKey(), rule.getKey().toString(), "xoo"));
  185. }
  186. @Test
  187. public void hide_author_if_not_member_of_organization() {
  188. UserDto user = db.users().insertUser();
  189. userSession.logIn(user);
  190. OrganizationDto organization = db.organizations().insert();
  191. ComponentDto project = db.components().insertPublicProject(organization);
  192. indexPermissions();
  193. ComponentDto file = db.components().insertComponent(newFileDto(project));
  194. RuleDefinitionDto rule = newRule().getDefinition();
  195. IssueDto issue = db.issues().insertIssue(rule, project, file, i -> i.setAuthorLogin("John"));
  196. indexIssues();
  197. SearchWsResponse response = ws.newRequest()
  198. .executeProtobuf(SearchWsResponse.class);
  199. assertThat(response.getIssuesList())
  200. .extracting(Issue::getKey, Issue::hasAuthor)
  201. .containsExactlyInAnyOrder(tuple(issue.getKey(), false));
  202. }
  203. @Test
  204. public void issue_with_cross_file_locations() {
  205. ComponentDto project = db.components().insertPublicProject();
  206. indexPermissions();
  207. ComponentDto file = db.components().insertComponent(newFileDto(project));
  208. ComponentDto anotherFile = db.components().insertComponent(newFileDto(project));
  209. DbIssues.Locations.Builder locations = DbIssues.Locations.newBuilder().addFlow(DbIssues.Flow.newBuilder().addAllLocation(Arrays.asList(
  210. DbIssues.Location.newBuilder()
  211. .setComponentId(file.uuid())
  212. .setMsg("FLOW MESSAGE")
  213. .setTextRange(DbCommons.TextRange.newBuilder()
  214. .setStartLine(1)
  215. .setEndLine(1)
  216. .setStartOffset(0)
  217. .setEndOffset(12)
  218. .build())
  219. .build(),
  220. DbIssues.Location.newBuilder()
  221. .setComponentId(anotherFile.uuid())
  222. .setMsg("ANOTHER FLOW MESSAGE")
  223. .setTextRange(DbCommons.TextRange.newBuilder()
  224. .setStartLine(1)
  225. .setEndLine(1)
  226. .setStartOffset(0)
  227. .setEndOffset(12)
  228. .build())
  229. .build(),
  230. DbIssues.Location.newBuilder()
  231. // .setComponentId(no component id set)
  232. .setMsg("FLOW MESSAGE WITHOUT FILE UUID")
  233. .setTextRange(DbCommons.TextRange.newBuilder()
  234. .setStartLine(1)
  235. .setEndLine(1)
  236. .setStartOffset(0)
  237. .setEndOffset(12)
  238. .build())
  239. .build())));
  240. RuleDefinitionDto rule = newRule().getDefinition();
  241. db.issues().insertIssue(rule, project, file, i -> i.setLocations(locations.build()));
  242. indexIssues();
  243. SearchWsResponse result = ws.newRequest().executeProtobuf(SearchWsResponse.class);
  244. assertThat(result.getIssuesCount()).isEqualTo(1);
  245. assertThat(result.getIssues(0).getFlows(0).getLocationsList()).extracting(Common.Location::getComponent, Common.Location::getMsg)
  246. .containsExactlyInAnyOrder(
  247. tuple(file.getKey(), "FLOW MESSAGE"),
  248. tuple(anotherFile.getKey(), "ANOTHER FLOW MESSAGE"),
  249. tuple(file.getKey(), "FLOW MESSAGE WITHOUT FILE UUID"));
  250. }
  251. @Test
  252. public void issue_with_comments() {
  253. UserDto john = db.users().insertUser(u -> u.setLogin("john").setName("John"));
  254. UserDto fabrice = db.users().insertUser(u -> u.setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com"));
  255. ComponentDto project = db.components().insertPublicProject();
  256. indexPermissions();
  257. ComponentDto file = db.components().insertComponent(newFileDto(project));
  258. RuleDefinitionDto rule = newRule().getDefinition();
  259. IssueDto issue = db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
  260. dbClient.issueChangeDao().insert(session,
  261. new IssueChangeDto().setIssueKey(issue.getKey())
  262. .setKey("COMMENT-ABCD")
  263. .setChangeData("*My comment*")
  264. .setChangeType(IssueChangeDto.TYPE_COMMENT)
  265. .setUserUuid(john.getUuid())
  266. .setIssueChangeCreationDate(parseDateTime("2014-09-09T12:00:00+0000").getTime()));
  267. dbClient.issueChangeDao().insert(session,
  268. new IssueChangeDto().setIssueKey(issue.getKey())
  269. .setKey("COMMENT-ABCE")
  270. .setChangeData("Another comment")
  271. .setChangeType(IssueChangeDto.TYPE_COMMENT)
  272. .setUserUuid(fabrice.getUuid())
  273. .setIssueChangeCreationDate(parseDateTime("2014-09-10T12:00:00+0000").getTime()));
  274. session.commit();
  275. indexIssues();
  276. userSession.logIn(john);
  277. ws.newRequest()
  278. .setParam("additionalFields", "comments,users")
  279. .execute()
  280. .assertJson(this.getClass(), "issue_with_comments.json");
  281. }
  282. @Test
  283. public void issue_with_comment_hidden() {
  284. UserDto john = db.users().insertUser(u -> u.setLogin("john").setName("John").setEmail("john@email.com"));
  285. UserDto fabrice = db.users().insertUser(u -> u.setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com"));
  286. ComponentDto project = db.components().insertPublicProject();
  287. indexPermissions();
  288. ComponentDto file = db.components().insertComponent(newFileDto(project));
  289. RuleDefinitionDto rule = newRule().getDefinition();
  290. IssueDto issue = db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
  291. dbClient.issueChangeDao().insert(session,
  292. new IssueChangeDto().setIssueKey(issue.getKey())
  293. .setKey("COMMENT-ABCD")
  294. .setChangeData("*My comment*")
  295. .setChangeType(IssueChangeDto.TYPE_COMMENT)
  296. .setUserUuid(john.getUuid())
  297. .setCreatedAt(parseDateTime("2014-09-09T12:00:00+0000").getTime()));
  298. dbClient.issueChangeDao().insert(session,
  299. new IssueChangeDto().setIssueKey(issue.getKey())
  300. .setKey("COMMENT-ABCE")
  301. .setChangeData("Another comment")
  302. .setChangeType(IssueChangeDto.TYPE_COMMENT)
  303. .setUserUuid(fabrice.getUuid())
  304. .setCreatedAt(parseDateTime("2014-09-10T19:10:03+0000").getTime()));
  305. session.commit();
  306. indexIssues();
  307. userSession.logIn(john);
  308. SearchWsResponse response = ws.newRequest()
  309. .setParam(PARAM_HIDE_COMMENTS, "true")
  310. .executeProtobuf(SearchWsResponse.class);
  311. assertThat(response.getIssuesList())
  312. .extracting(Issue::getKey, i -> i.getComments().getCommentsList())
  313. .containsExactlyInAnyOrder(tuple(issue.getKey(), Collections.emptyList()));
  314. }
  315. @Test
  316. public void load_additional_fields() {
  317. UserDto simon = db.users().insertUser(u -> u.setLogin("simon").setName("Simon").setEmail("simon@email.com"));
  318. ComponentDto project = db.components().insertPublicProject();
  319. indexPermissions();
  320. ComponentDto file = db.components().insertComponent(newFileDto(project));
  321. RuleDefinitionDto rule = newRule().getDefinition();
  322. db.issues().insertIssue(rule, project, file, i -> i.setAssigneeUuid(simon.getUuid()).setType(CODE_SMELL));
  323. indexIssues();
  324. userSession.logIn("john");
  325. ws.newRequest()
  326. .setParam("additionalFields", "_all").execute()
  327. .assertJson(this.getClass(), "load_additional_fields.json");
  328. }
  329. @Test
  330. public void load_additional_fields_with_issue_admin_permission() {
  331. UserDto simon = db.users().insertUser(u -> u.setLogin("simon").setName("Simon").setEmail("simon@email.com"));
  332. UserDto fabrice = db.users().insertUser(u -> u.setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com"));
  333. OrganizationDto organization = db.organizations().insert(o -> o.setKey("my-org-1"));
  334. ComponentDto project = db.components().insertComponent(ComponentTesting.newPublicProjectDto(organization, "PROJECT_ID").setDbKey("PROJECT_KEY").setLanguage("java"));
  335. grantPermissionToAnyone(project, ISSUE_ADMIN);
  336. indexPermissions();
  337. ComponentDto file = db.components().insertComponent(newFileDto(project, null, "FILE_ID").setDbKey("FILE_KEY").setLanguage("js"));
  338. IssueDto issue = newDto(newRule(), file, project)
  339. .setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")
  340. .setAuthorLogin(fabrice.getLogin())
  341. .setAssigneeUuid(simon.getUuid())
  342. .setType(CODE_SMELL);
  343. dbClient.issueDao().insert(session, issue);
  344. session.commit();
  345. indexIssues();
  346. userSession.logIn("john")
  347. .addProjectPermission(ISSUE_ADMIN, project); // granted by Anyone
  348. ws.newRequest()
  349. .setParam("additionalFields", "_all").execute()
  350. .assertJson(this.getClass(), "load_additional_fields_with_issue_admin_permission.json");
  351. }
  352. @Test
  353. public void search_by_rule_key() {
  354. RuleDto rule = newRule();
  355. OrganizationDto organization = db.organizations().insert(o -> o.setKey("my-org-1"));
  356. ComponentDto project = db.components().insertComponent(ComponentTesting.newPublicProjectDto(organization, "PROJECT_ID").setDbKey("PROJECT_KEY").setLanguage("java"));
  357. ComponentDto file = db.components().insertComponent(newFileDto(project, null, "FILE_ID").setDbKey("FILE_KEY").setLanguage("java"));
  358. db.issues().insertIssue(rule.getDefinition(), project, file);
  359. session.commit();
  360. indexIssues();
  361. userSession.logIn("john")
  362. .addProjectPermission(ISSUE_ADMIN, project); // granted by Anyone
  363. indexPermissions();
  364. TestResponse execute = ws.newRequest()
  365. .setParam(PARAM_RULES, rule.getKey().toString())
  366. .setParam("additionalFields", "_all")
  367. .execute();
  368. execute.assertJson(this.getClass(), "result_for_rule_search.json");
  369. }
  370. @Test
  371. public void issue_on_removed_file() {
  372. RuleDto rule = newRule();
  373. OrganizationDto organization = db.organizations().insert(o -> o.setKey("my-org-2"));
  374. ComponentDto project = db.components().insertComponent(ComponentTesting.newPublicProjectDto(organization, "PROJECT_ID").setDbKey("PROJECT_KEY"));
  375. indexPermissions();
  376. ComponentDto removedFile = db.components().insertComponent(newFileDto(project, null).setUuid("REMOVED_FILE_ID")
  377. .setDbKey("REMOVED_FILE_KEY")
  378. .setEnabled(false));
  379. IssueDto issue = newDto(rule, removedFile, project)
  380. .setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")
  381. .setComponent(removedFile)
  382. .setStatus("OPEN").setResolution("OPEN")
  383. .setSeverity("MAJOR")
  384. .setIssueCreationDate(parseDateTime("2014-09-04T00:00:00+0100"))
  385. .setIssueUpdateDate(parseDateTime("2017-12-04T00:00:00+0100"));
  386. dbClient.issueDao().insert(session, issue);
  387. session.commit();
  388. indexIssues();
  389. ws.newRequest()
  390. .execute()
  391. .assertJson(this.getClass(), "issue_on_removed_file.json");
  392. }
  393. @Test
  394. public void apply_paging_with_one_component() {
  395. RuleDto rule = newRule();
  396. OrganizationDto organization = db.organizations().insert(o -> o.setKey("my-org-2"));
  397. ComponentDto project = db.components().insertComponent(ComponentTesting.newPublicProjectDto(organization, "PROJECT_ID").setDbKey("PROJECT_KEY"));
  398. indexPermissions();
  399. ComponentDto file = db.components().insertComponent(newFileDto(project, null, "FILE_ID").setDbKey("FILE_KEY"));
  400. for (int i = 0; i < SearchOptions.MAX_LIMIT + 1; i++) {
  401. IssueDto issue = newDto(rule, file, project).setAssigneeUuid(null);
  402. dbClient.issueDao().insert(session, issue);
  403. }
  404. session.commit();
  405. indexIssues();
  406. ws.newRequest().setParam(PARAM_COMPONENT_KEYS, file.getKey()).execute()
  407. .assertJson(this.getClass(), "apply_paging_with_one_component.json");
  408. }
  409. @Test
  410. public void components_contains_sub_projects() {
  411. OrganizationDto organization = db.organizations().insert(o -> o.setKey("my-org-1"));
  412. ComponentDto project = db.components().insertComponent(ComponentTesting.newPublicProjectDto(organization, "PROJECT_ID").setDbKey("ProjectHavingModule"));
  413. indexPermissions();
  414. ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project).setDbKey("ModuleHavingFile"));
  415. ComponentDto file = db.components().insertComponent(newFileDto(module, null, "BCDE").setDbKey("FileLinkedToModule"));
  416. IssueDto issue = newDto(newRule(), file, project);
  417. dbClient.issueDao().insert(session, issue);
  418. session.commit();
  419. indexIssues();
  420. ws.newRequest().setParam(PARAM_ADDITIONAL_FIELDS, "_all").execute()
  421. .assertJson(this.getClass(), "components_contains_sub_projects.json");
  422. }
  423. @Test
  424. public void filter_by_assigned_to_me() {
  425. UserDto john = db.users().insertUser(u -> u.setLogin("john").setName("John").setEmail("john@email.com"));
  426. UserDto alice = db.users().insertUser(u -> u.setLogin("alice").setName("Alice").setEmail("alice@email.com"));
  427. OrganizationDto organization = db.organizations().insert();
  428. ComponentDto project = db.components().insertComponent(ComponentTesting.newPublicProjectDto(organization, "PROJECT_ID").setDbKey("PROJECT_KEY"));
  429. indexPermissions();
  430. ComponentDto file = db.components().insertComponent(newFileDto(project, null, "FILE_ID").setDbKey("FILE_KEY"));
  431. RuleDto rule = newRule();
  432. IssueDto issue1 = newDto(rule, file, project)
  433. .setIssueCreationDate(parseDate("2014-09-04"))
  434. .setIssueUpdateDate(parseDate("2017-12-04"))
  435. .setEffort(10L)
  436. .setStatus("OPEN")
  437. .setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")
  438. .setSeverity("MAJOR")
  439. .setAssigneeUuid(john.getUuid());
  440. IssueDto issue2 = newDto(rule, file, project)
  441. .setIssueCreationDate(parseDate("2014-09-04"))
  442. .setIssueUpdateDate(parseDate("2017-12-04"))
  443. .setEffort(10L)
  444. .setStatus("OPEN")
  445. .setKee("7b112bd4-b650-4037-80bc-82fd47d4eac2")
  446. .setSeverity("MAJOR")
  447. .setAssigneeUuid(alice.getUuid());
  448. IssueDto issue3 = newDto(rule, file, project)
  449. .setIssueCreationDate(parseDate("2014-09-04"))
  450. .setIssueUpdateDate(parseDate("2017-12-04"))
  451. .setEffort(10L)
  452. .setStatus("OPEN")
  453. .setKee("82fd47d4-4037-b650-80bc-7b112bd4eac2")
  454. .setSeverity("MAJOR")
  455. .setAssigneeUuid(null);
  456. dbClient.issueDao().insert(session, issue1, issue2, issue3);
  457. session.commit();
  458. indexIssues();
  459. userSession.logIn(john);
  460. ws.newRequest()
  461. .setParam("resolved", "false")
  462. .setParam("assignees", "__me__")
  463. .setParam(FACETS, "assignees,assigned_to_me")
  464. .execute()
  465. .assertJson(this.getClass(), "filter_by_assigned_to_me.json");
  466. }
  467. @Test
  468. public void return_empty_when_login_is_unknown() {
  469. UserDto john = db.users().insertUser(u -> u.setLogin("john").setName("John").setEmail("john@email.com"));
  470. UserDto alice = db.users().insertUser(u -> u.setLogin("alice").setName("Alice").setEmail("alice@email.com"));
  471. OrganizationDto organization = db.organizations().insert();
  472. ComponentDto project = db.components().insertComponent(ComponentTesting.newPublicProjectDto(organization, "PROJECT_ID").setDbKey("PROJECT_KEY"));
  473. indexPermissions();
  474. ComponentDto file = db.components().insertComponent(newFileDto(project, null, "FILE_ID").setDbKey("FILE_KEY"));
  475. RuleDto rule = newRule();
  476. IssueDto issue1 = newDto(rule, file, project)
  477. .setIssueCreationDate(parseDate("2014-09-04"))
  478. .setIssueUpdateDate(parseDate("2017-12-04"))
  479. .setEffort(10L)
  480. .setStatus("OPEN")
  481. .setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")
  482. .setSeverity("MAJOR")
  483. .setAssigneeUuid(john.getUuid());
  484. IssueDto issue2 = newDto(rule, file, project)
  485. .setIssueCreationDate(parseDate("2014-09-04"))
  486. .setIssueUpdateDate(parseDate("2017-12-04"))
  487. .setEffort(10L)
  488. .setStatus("OPEN")
  489. .setKee("7b112bd4-b650-4037-80bc-82fd47d4eac2")
  490. .setSeverity("MAJOR")
  491. .setAssigneeUuid(alice.getUuid());
  492. IssueDto issue3 = newDto(rule, file, project)
  493. .setIssueCreationDate(parseDate("2014-09-04"))
  494. .setIssueUpdateDate(parseDate("2017-12-04"))
  495. .setEffort(10L)
  496. .setStatus("OPEN")
  497. .setKee("82fd47d4-4037-b650-80bc-7b112bd4eac2")
  498. .setSeverity("MAJOR")
  499. .setAssigneeUuid(null);
  500. dbClient.issueDao().insert(session, issue1, issue2, issue3);
  501. session.commit();
  502. indexIssues();
  503. userSession.logIn(john);
  504. SearchWsResponse response = ws.newRequest()
  505. .setParam("resolved", "false")
  506. .setParam("assignees", "unknown")
  507. .setParam(FACETS, "assignees")
  508. .executeProtobuf(SearchWsResponse.class);
  509. assertThat(response.getIssuesList()).isEmpty();
  510. }
  511. @Test
  512. public void filter_by_assigned_to_me_when_not_authenticate() {
  513. UserDto poy = db.users().insertUser(u -> u.setLogin("poy").setName("poypoy").setEmail("poypoy@email.com"));
  514. userSession.logIn(poy);
  515. UserDto alice = db.users().insertUser(u -> u.setLogin("alice").setName("Alice").setEmail("alice@email.com"));
  516. UserDto john = db.users().insertUser(u -> u.setLogin("john").setName("John").setEmail("john@email.com"));
  517. OrganizationDto organization = db.organizations().insert(o -> o.setKey("my-org-1"));
  518. ComponentDto project = db.components().insertComponent(ComponentTesting.newPublicProjectDto(organization, "PROJECT_ID").setDbKey("PROJECT_KEY"));
  519. indexPermissions();
  520. ComponentDto file = db.components().insertComponent(newFileDto(project, null, "FILE_ID").setDbKey("FILE_KEY"));
  521. RuleDto rule = newRule();
  522. IssueDto issue1 = newDto(rule, file, project)
  523. .setStatus("OPEN")
  524. .setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")
  525. .setAssigneeUuid(john.getUuid());
  526. IssueDto issue2 = newDto(rule, file, project)
  527. .setStatus("OPEN")
  528. .setKee("7b112bd4-b650-4037-80bc-82fd47d4eac2")
  529. .setAssigneeUuid(alice.getUuid());
  530. IssueDto issue3 = newDto(rule, file, project)
  531. .setStatus("OPEN")
  532. .setKee("82fd47d4-4037-b650-80bc-7b112bd4eac2")
  533. .setAssigneeUuid(null);
  534. dbClient.issueDao().insert(session, issue1, issue2, issue3);
  535. session.commit();
  536. indexIssues();
  537. ws.newRequest()
  538. .setParam("resolved", "false")
  539. .setParam("assignees", "__me__")
  540. .execute()
  541. .assertJson(this.getClass(), "empty_result.json");
  542. }
  543. @Test
  544. public void search_by_author() {
  545. ComponentDto project = db.components().insertPublicProject();
  546. ComponentDto file = db.components().insertComponent(newFileDto(project, null));
  547. RuleDefinitionDto rule = db.rules().insertIssueRule();
  548. IssueDto issue1 = db.issues().insertIssue(rule, project, file, i -> i.setAuthorLogin("leia"));
  549. IssueDto issue2 = db.issues().insertIssue(rule, project, file, i -> i.setAuthorLogin("luke"));
  550. IssueDto issue3 = db.issues().insertIssue(rule, project, file, i -> i.setAuthorLogin("han, solo"));
  551. indexPermissions();
  552. indexIssues();
  553. SearchWsResponse response = ws.newRequest()
  554. .setMultiParam("author", asList("leia", "han, solo"))
  555. .setParam(FACETS, "author")
  556. .executeProtobuf(SearchWsResponse.class);
  557. assertThat(response.getIssuesList())
  558. .extracting(Issue::getKey)
  559. .containsExactlyInAnyOrder(issue1.getKey(), issue3.getKey());
  560. Common.Facet facet = response.getFacets().getFacetsList().get(0);
  561. assertThat(facet.getProperty()).isEqualTo("author");
  562. assertThat(facet.getValuesList())
  563. .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
  564. .containsExactlyInAnyOrder(
  565. tuple("leia", 1L),
  566. tuple("luke", 1L),
  567. tuple("han, solo", 1L));
  568. assertThat(ws.newRequest()
  569. .setMultiParam("author", singletonList("unknown"))
  570. .executeProtobuf(SearchWsResponse.class).getIssuesList())
  571. .isEmpty();
  572. }
  573. @Test
  574. public void search_by_deprecated_authors_parameter() {
  575. ComponentDto project = db.components().insertPublicProject();
  576. ComponentDto file = db.components().insertComponent(newFileDto(project, null));
  577. RuleDefinitionDto rule = db.rules().insertIssueRule();
  578. IssueDto issue1 = db.issues().insertIssue(rule, project, file, i -> i.setAuthorLogin("leia"));
  579. IssueDto issue2 = db.issues().insertIssue(rule, project, file, i -> i.setAuthorLogin("luke"));
  580. indexPermissions();
  581. indexIssues();
  582. SearchWsResponse response = ws.newRequest()
  583. .setParam("authors", "leia")
  584. .setParam(FACETS, "authors")
  585. .executeProtobuf(SearchWsResponse.class);
  586. assertThat(response.getIssuesList()).extracting(Issue::getKey).containsExactlyInAnyOrder(issue1.getKey());
  587. Common.Facet facet = response.getFacets().getFacetsList().get(0);
  588. assertThat(facet.getProperty()).isEqualTo("authors");
  589. assertThat(facet.getValuesList())
  590. .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
  591. .containsExactlyInAnyOrder(
  592. tuple("leia", 1L),
  593. tuple("luke", 1L));
  594. // Deprecated parameter 'authors' will be ignored if new parameter 'author' is set
  595. assertThat(ws.newRequest()
  596. .setMultiParam("author", singletonList("luke"))
  597. // This parameter will be ignored
  598. .setParam("authors", "leia")
  599. .executeProtobuf(SearchWsResponse.class).getIssuesList())
  600. .extracting(Issue::getKey)
  601. .containsExactlyInAnyOrder(issue2.getKey());
  602. }
  603. @Test
  604. public void sort_by_updated_at() {
  605. RuleDto rule = newRule();
  606. OrganizationDto organization = db.organizations().insert(o -> o.setKey("my-org-2"));
  607. ComponentDto project = db.components().insertComponent(ComponentTesting.newPublicProjectDto(organization, "PROJECT_ID").setDbKey("PROJECT_KEY"));
  608. indexPermissions();
  609. ComponentDto file = db.components().insertComponent(newFileDto(project, null, "FILE_ID").setDbKey("FILE_KEY"));
  610. dbClient.issueDao().insert(session, newDto(rule, file, project)
  611. .setKee("82fd47d4-b650-4037-80bc-7b112bd4eac1")
  612. .setIssueUpdateDate(parseDateTime("2014-11-02T00:00:00+0100")));
  613. dbClient.issueDao().insert(session, newDto(rule, file, project)
  614. .setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")
  615. .setIssueUpdateDate(parseDateTime("2014-11-01T00:00:00+0100")));
  616. dbClient.issueDao().insert(session, newDto(rule, file, project)
  617. .setKee("82fd47d4-b650-4037-80bc-7b112bd4eac3")
  618. .setIssueUpdateDate(parseDateTime("2014-11-03T00:00:00+0100")));
  619. session.commit();
  620. indexIssues();
  621. TestResponse response = ws.newRequest()
  622. .setParam("s", IssueQuery.SORT_BY_UPDATE_DATE)
  623. .setParam("asc", "false")
  624. .execute();
  625. JsonElement parse = new JsonParser().parse(response.getInput());
  626. assertThat(parse.getAsJsonObject().get("issues").getAsJsonArray())
  627. .extracting(o -> o.getAsJsonObject().get("key").getAsString())
  628. .containsExactly("82fd47d4-b650-4037-80bc-7b112bd4eac3", "82fd47d4-b650-4037-80bc-7b112bd4eac1", "82fd47d4-b650-4037-80bc-7b112bd4eac2");
  629. }
  630. @Test
  631. public void security_hotspots_are_not_returned_by_default() {
  632. ComponentDto project = db.components().insertPublicProject();
  633. ComponentDto file = db.components().insertComponent(newFileDto(project));
  634. RuleDefinitionDto rule = db.rules().insertIssueRule();
  635. db.issues().insertIssue(rule, project, file, i -> i.setType(RuleType.BUG));
  636. db.issues().insertIssue(rule, project, file, i -> i.setType(RuleType.VULNERABILITY));
  637. db.issues().insertIssue(rule, project, file, i -> i.setType(CODE_SMELL));
  638. db.issues().insertHotspot(project, file);
  639. indexPermissions();
  640. indexIssues();
  641. SearchWsResponse result = ws.newRequest().executeProtobuf(SearchWsResponse.class);
  642. assertThat(result.getIssuesList())
  643. .extracting(Issue::getType)
  644. .containsExactlyInAnyOrder(BUG, VULNERABILITY, Common.RuleType.CODE_SMELL);
  645. }
  646. @Test
  647. public void security_hotspots_are_not_returned_by_issues_param() {
  648. ComponentDto project = db.components().insertPublicProject();
  649. ComponentDto file = db.components().insertComponent(newFileDto(project));
  650. RuleDefinitionDto issueRule = db.rules().insertIssueRule();
  651. IssueDto bugIssue = db.issues().insertIssue(issueRule, project, file, i -> i.setType(RuleType.BUG));
  652. IssueDto vulnerabilityIssue = db.issues().insertIssue(issueRule, project, file, i -> i.setType(RuleType.VULNERABILITY));
  653. IssueDto codeSmellIssue = db.issues().insertIssue(issueRule, project, file, i -> i.setType(CODE_SMELL));
  654. RuleDefinitionDto hotspotRule = db.rules().insertHotspotRule();
  655. IssueDto hotspot = db.issues().insertHotspot(hotspotRule, project, file);
  656. indexPermissions();
  657. indexIssues();
  658. SearchWsResponse result = ws.newRequest()
  659. .setParam("issues", Stream.of(bugIssue, vulnerabilityIssue, codeSmellIssue, hotspot).map(IssueDto::getKey).collect(Collectors.joining(",")))
  660. .executeProtobuf(SearchWsResponse.class);
  661. assertThat(result.getIssuesList())
  662. .extracting(Issue::getType)
  663. .containsExactlyInAnyOrder(BUG, VULNERABILITY, Common.RuleType.CODE_SMELL);
  664. }
  665. @Test
  666. public void security_hotspots_are_not_returned_by_cwe() {
  667. ComponentDto project = db.components().insertPublicProject();
  668. ComponentDto file = db.components().insertComponent(newFileDto(project));
  669. Consumer<RuleDefinitionDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
  670. .setSecurityStandards(Sets.newHashSet("cwe:20", "cwe:564", "cwe:89", "cwe:943", "owaspTop10:a1"))
  671. .setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
  672. Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
  673. RuleDefinitionDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
  674. db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
  675. RuleDefinitionDto issueRule = db.rules().insertIssueRule(ruleConsumer);
  676. IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer);
  677. IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer);
  678. indexPermissions();
  679. indexIssues();
  680. SearchWsResponse result = ws.newRequest()
  681. .setParam("cwe", "20")
  682. .executeProtobuf(SearchWsResponse.class);
  683. assertThat(result.getIssuesList())
  684. .extracting(Issue::getKey)
  685. .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey());
  686. }
  687. @Test
  688. public void security_hotspots_are_not_returned_by_assignees() {
  689. UserDto user = db.users().insertUser();
  690. ComponentDto project = db.components().insertPublicProject();
  691. ComponentDto file = db.components().insertComponent(newFileDto(project));
  692. RuleDefinitionDto rule = db.rules().insertIssueRule();
  693. db.issues().insertHotspot(rule, project, file, issueDto -> issueDto.setAssigneeUuid(user.getUuid()));
  694. IssueDto issueDto1 = db.issues().insertIssue(rule, project, file, issueDto -> issueDto.setAssigneeUuid(user.getUuid()));
  695. IssueDto issueDto2 = db.issues().insertIssue(rule, project, file, issueDto -> issueDto.setAssigneeUuid(user.getUuid()));
  696. IssueDto issueDto3 = db.issues().insertIssue(rule, project, file, issueDto -> issueDto.setAssigneeUuid(user.getUuid()));
  697. IssueDto issueDto4 = db.issues().insertIssue(rule, project, file, issueDto -> issueDto.setAssigneeUuid(user.getUuid()));
  698. indexPermissions();
  699. indexIssues();
  700. SearchWsResponse result = ws.newRequest()
  701. .setParam(PARAM_ASSIGNEES, user.getLogin())
  702. .executeProtobuf(SearchWsResponse.class);
  703. assertThat(result.getIssuesList())
  704. .extracting(Issue::getKey)
  705. .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey(), issueDto3.getKey(), issueDto4.getKey());
  706. }
  707. @Test
  708. public void security_hotspots_are_not_returned_by_rule() {
  709. ComponentDto project = db.components().insertPublicProject();
  710. ComponentDto file = db.components().insertComponent(newFileDto(project));
  711. RuleDefinitionDto hotspotRule = db.rules().insertHotspotRule();
  712. db.issues().insertHotspot(hotspotRule, project, file);
  713. indexPermissions();
  714. indexIssues();
  715. SearchWsResponse result = ws.newRequest()
  716. .setParam("rules", hotspotRule.getKey().toString())
  717. .executeProtobuf(SearchWsResponse.class);
  718. assertThat(result.getIssuesList()).isEmpty();
  719. }
  720. @Test
  721. public void security_hotspots_are_not_returned_by_issues_param_only() {
  722. ComponentDto project = db.components().insertPublicProject();
  723. ComponentDto file = db.components().insertComponent(newFileDto(project));
  724. RuleDefinitionDto rule = db.rules().insertIssueRule();
  725. List<IssueDto> hotspots = IntStream.range(1, 2 + new Random().nextInt(10))
  726. .mapToObj(value -> db.issues().insertHotspot(rule, project, file))
  727. .collect(Collectors.toList());
  728. indexPermissions();
  729. indexIssues();
  730. SearchWsResponse result = ws.newRequest()
  731. .setParam("issues", hotspots.stream().map(IssueDto::getKey).collect(Collectors.joining(",")))
  732. .executeProtobuf(SearchWsResponse.class);
  733. assertThat(result.getIssuesList())
  734. .isEmpty();
  735. }
  736. @Test
  737. public void fail_if_trying_to_filter_issues_by_hotspots() {
  738. ComponentDto project = db.components().insertPublicProject();
  739. ComponentDto file = db.components().insertComponent(newFileDto(project));
  740. RuleDefinitionDto rule = newRule().getDefinition();
  741. db.issues().insertIssue(rule, project, file, i -> i.setType(RuleType.BUG));
  742. db.issues().insertIssue(rule, project, file, i -> i.setType(RuleType.VULNERABILITY));
  743. db.issues().insertIssue(rule, project, file, i -> i.setType(CODE_SMELL));
  744. db.issues().insertHotspot(rule, project, file);
  745. indexPermissions();
  746. indexIssues();
  747. assertThatThrownBy(() -> ws.newRequest()
  748. .setParam("types", RuleType.SECURITY_HOTSPOT.toString())
  749. .execute())
  750. .isInstanceOf(IllegalArgumentException.class)
  751. .hasMessage("Value of parameter 'types' (SECURITY_HOTSPOT) must be one of: [CODE_SMELL, BUG, VULNERABILITY]");
  752. }
  753. @Test
  754. public void security_hotspot_are_ignored_when_filtering_by_severities() {
  755. ComponentDto project = db.components().insertPublicProject();
  756. ComponentDto file = db.components().insertComponent(newFileDto(project));
  757. RuleDefinitionDto issueRule = db.rules().insertIssueRule();
  758. IssueDto bugIssue = db.issues().insertIssue(issueRule, project, file, i -> i.setType(RuleType.BUG).setSeverity(Severity.MAJOR.name()));
  759. IssueDto vulnerabilityIssue = db.issues().insertIssue(issueRule, project, file, i -> i.setType(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR.name()));
  760. IssueDto codeSmellIssue = db.issues().insertIssue(issueRule, project, file, i -> i.setType(CODE_SMELL).setSeverity(Severity.MAJOR.name()));
  761. RuleDefinitionDto hotspotRule = db.rules().insertHotspotRule();
  762. db.issues().insertHotspot(hotspotRule, project, file, i -> i.setSeverity(Severity.MAJOR.name()));
  763. indexPermissions();
  764. indexIssues();
  765. SearchWsResponse result = ws.newRequest()
  766. .setParam("severities", Severity.MAJOR.name())
  767. .setParam(FACETS, "severities")
  768. .executeProtobuf(SearchWsResponse.class);
  769. assertThat(result.getIssuesList())
  770. .extracting(Issue::getKey, Issue::getType)
  771. .containsExactlyInAnyOrder(
  772. tuple(bugIssue.getKey(), BUG),
  773. tuple(vulnerabilityIssue.getKey(), VULNERABILITY),
  774. tuple(codeSmellIssue.getKey(), Common.RuleType.CODE_SMELL));
  775. assertThat(result.getFacets().getFacets(0).getValuesList())
  776. .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
  777. .containsExactlyInAnyOrder(tuple("MAJOR", 3L), tuple("INFO", 0L), tuple("MINOR", 0L), tuple("CRITICAL", 0L), tuple("BLOCKER", 0L));
  778. }
  779. @Test
  780. public void return_total_effort() {
  781. UserDto john = db.users().insertUser();
  782. userSession.logIn(john);
  783. RuleDefinitionDto rule = db.rules().insertIssueRule();
  784. ComponentDto project = db.components().insertPublicProject();
  785. ComponentDto file = db.components().insertComponent(newFileDto(project));
  786. IssueDto issue1 = db.issues().insertIssue(rule, project, file, i -> i.setEffort(10L));
  787. IssueDto issue2 = db.issues().insertIssue(rule, project, file, i -> i.setEffort(15L));
  788. indexPermissions();
  789. indexIssues();
  790. SearchWsResponse response = ws.newRequest().executeProtobuf(SearchWsResponse.class);
  791. assertThat(response.getEffortTotal()).isEqualTo(25L);
  792. }
  793. @Test
  794. public void paging() {
  795. RuleDto rule = newRule();
  796. OrganizationDto organization = db.organizations().insert(o -> o.setKey("my-org-1"));
  797. ComponentDto project = db.components().insertComponent(ComponentTesting.newPublicProjectDto(organization, "PROJECT_ID").setDbKey("PROJECT_KEY"));
  798. indexPermissions();
  799. ComponentDto file = db.components().insertComponent(newFileDto(project, null, "FILE_ID").setDbKey("FILE_KEY"));
  800. for (int i = 0; i < 12; i++) {
  801. IssueDto issue = newDto(rule, file, project);
  802. dbClient.issueDao().insert(session, issue);
  803. }
  804. session.commit();
  805. indexIssues();
  806. ws.newRequest()
  807. .setParam(WebService.Param.PAGE, "2")
  808. .setParam(WebService.Param.PAGE_SIZE, "9")
  809. .execute()
  810. .assertJson(this.getClass(), "paging.json");
  811. }
  812. @Test
  813. public void paging_with_page_size_to_minus_one() {
  814. RuleDto rule = newRule();
  815. OrganizationDto organization = db.organizations().insert(o -> o.setKey("my-org-1"));
  816. ComponentDto project = db.components().insertComponent(ComponentTesting.newPublicProjectDto(organization, "PROJECT_ID").setDbKey("PROJECT_KEY"));
  817. indexPermissions();
  818. ComponentDto file = db.components().insertComponent(newFileDto(project, null, "FILE_ID").setDbKey("FILE_KEY"));
  819. for (int i = 0; i < 12; i++) {
  820. IssueDto issue = newDto(rule, file, project);
  821. dbClient.issueDao().insert(session, issue);
  822. }
  823. session.commit();
  824. indexIssues();
  825. ws.newRequest()
  826. .setParam(WebService.Param.PAGE, "1")
  827. .setParam(WebService.Param.PAGE_SIZE, "-1")
  828. .execute()
  829. .assertJson(this.getClass(), "paging_with_page_size_to_minus_one.json");
  830. }
  831. @Test
  832. public void default_page_size_is_100() {
  833. ws.newRequest()
  834. .execute()
  835. .assertJson(this.getClass(), "default_page_size_is_100.json");
  836. }
  837. // SONAR-10217
  838. @Test
  839. public void empty_search_with_unknown_branch() {
  840. SearchWsResponse response = ws.newRequest()
  841. .setParam("onComponentOnly", "true")
  842. .setParam("componentKeys", "foo")
  843. .setParam("branch", "bar")
  844. .executeProtobuf(SearchWsResponse.class);
  845. assertThat(response)
  846. .extracting(SearchWsResponse::getIssuesList, r -> r.getPaging().getTotal())
  847. .containsExactlyInAnyOrder(Collections.emptyList(), 0);
  848. }
  849. @Test
  850. public void empty_search() {
  851. SearchWsResponse response = ws.newRequest().executeProtobuf(SearchWsResponse.class);
  852. assertThat(response)
  853. .extracting(SearchWsResponse::getIssuesList, r -> r.getPaging().getTotal())
  854. .containsExactlyInAnyOrder(Collections.emptyList(), 0);
  855. }
  856. @Test
  857. public void fail_when_invalid_format() {
  858. expectedException.expect(IllegalArgumentException.class);
  859. expectedException.expectMessage("Date 'wrong-date-input' cannot be parsed as either a date or date+time");
  860. ws.newRequest()
  861. .setParam(PARAM_CREATED_AFTER, "wrong-date-input")
  862. .execute();
  863. }
  864. @Test
  865. public void test_definition() {
  866. WebService.Action def = ws.getDef();
  867. assertThat(def.key()).isEqualTo("search");
  868. assertThat(def.isInternal()).isFalse();
  869. assertThat(def.isPost()).isFalse();
  870. assertThat(def.since()).isEqualTo("3.6");
  871. assertThat(def.responseExampleAsString()).isNotEmpty();
  872. assertThat(def.params()).extracting("key").containsExactlyInAnyOrder(
  873. "additionalFields", "asc", "assigned", "assignees", "authors", "author", "componentKeys", "componentUuids", "branch",
  874. "pullRequest", "organization",
  875. "createdAfter", "createdAt", "createdBefore", "createdInLast", "directories", "facetMode", "facets", "fileUuids", "issues", "languages", "moduleUuids", "onComponentOnly",
  876. "p", "projects", "ps", "resolutions", "resolved", "rules", "s", "severities", "sinceLeakPeriod",
  877. "statuses", "tags", "types", "owaspTop10", "sansTop25", "cwe", "sonarsourceSecurity");
  878. assertThat(def.param("organization"))
  879. .matches(WebService.Param::isInternal)
  880. .matches(p -> p.since().equals("6.4"));
  881. WebService.Param branch = def.param(PARAM_BRANCH);
  882. assertThat(branch.isInternal()).isTrue();
  883. assertThat(branch.isRequired()).isFalse();
  884. assertThat(branch.since()).isEqualTo("6.6");
  885. WebService.Param projectUuids = def.param("projects");
  886. assertThat(projectUuids.description()).isEqualTo("To retrieve issues associated to a specific list of projects (comma-separated list of project keys). " +
  887. "This parameter is mostly used by the Issues page, please prefer usage of the componentKeys parameter. If this parameter is set, projectUuids must not be set.");
  888. }
  889. private RuleDto newRule() {
  890. RuleDto rule = RuleTesting.newXooX1()
  891. .setName("Rule name")
  892. .setDescription("Rule desc")
  893. .setStatus(RuleStatus.READY);
  894. db.rules().insert(rule.getDefinition());
  895. return rule;
  896. }
  897. private void indexPermissions() {
  898. permissionIndexer.indexOnStartup(permissionIndexer.getIndexTypes());
  899. }
  900. private void indexIssues() {
  901. issueIndexer.indexOnStartup(issueIndexer.getIndexTypes());
  902. }
  903. private void grantPermissionToAnyone(ComponentDto project, String permission) {
  904. dbClient.groupPermissionDao().insert(session,
  905. new GroupPermissionDto()
  906. .setOrganizationUuid(project.getOrganizationUuid())
  907. .setGroupId(null)
  908. .setResourceId(project.getId())
  909. .setRole(permission));
  910. session.commit();
  911. userSession.logIn().addProjectPermission(permission, project);
  912. }
  913. }