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.

IssueIndexFiltersTest.java 48KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956
  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.issue.index;
  21. import java.util.Date;
  22. import java.util.List;
  23. import java.util.Map;
  24. import java.util.Set;
  25. import org.assertj.core.api.Fail;
  26. import org.junit.Test;
  27. import org.sonar.api.issue.Issue;
  28. import org.sonar.api.rule.Severity;
  29. import org.sonar.api.rules.RuleType;
  30. import org.sonar.core.issue.status.SimpleStatus;
  31. import org.sonar.db.component.ComponentDto;
  32. import org.sonar.db.rule.RuleDto;
  33. import org.sonar.server.es.SearchOptions;
  34. import org.sonar.server.security.SecurityStandards.SQCategory;
  35. import org.sonar.server.view.index.ViewDoc;
  36. import static java.util.Arrays.asList;
  37. import static java.util.Collections.emptyList;
  38. import static java.util.Collections.singletonList;
  39. import static org.assertj.core.api.Assertions.assertThat;
  40. import static org.assertj.core.api.Assertions.assertThatThrownBy;
  41. import static org.sonar.api.issue.impact.SoftwareQuality.MAINTAINABILITY;
  42. import static org.sonar.api.issue.impact.SoftwareQuality.RELIABILITY;
  43. import static org.sonar.api.issue.impact.SoftwareQuality.SECURITY;
  44. import static org.sonar.api.resources.Qualifiers.APP;
  45. import static org.sonar.api.rules.CleanCodeAttributeCategory.ADAPTABLE;
  46. import static org.sonar.api.rules.CleanCodeAttributeCategory.CONSISTENT;
  47. import static org.sonar.api.rules.CleanCodeAttributeCategory.INTENTIONAL;
  48. import static org.sonar.api.rules.CleanCodeAttributeCategory.RESPONSIBLE;
  49. import static org.sonar.api.utils.DateUtils.addDays;
  50. import static org.sonar.api.utils.DateUtils.parseDate;
  51. import static org.sonar.api.utils.DateUtils.parseDateTime;
  52. import static org.sonar.db.component.ComponentTesting.newFileDto;
  53. import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
  54. import static org.sonar.db.rule.RuleTesting.newRule;
  55. import static org.sonar.server.issue.IssueDocTesting.newDoc;
  56. import static org.sonar.server.issue.IssueDocTesting.newDocForProject;
  57. public class IssueIndexFiltersTest extends IssueIndexTestCommon {
  58. @Test
  59. public void filter_by_keys() {
  60. ComponentDto project = newPrivateProjectDto();
  61. indexIssues(
  62. newDoc("I1", project.uuid(), newFileDto(project)),
  63. newDoc("I2", project.uuid(), newFileDto(project)));
  64. assertThatSearchReturnsOnly(IssueQuery.builder().issueKeys(asList("I1", "I2")), "I1", "I2");
  65. assertThatSearchReturnsOnly(IssueQuery.builder().issueKeys(singletonList("I1")), "I1");
  66. assertThatSearchReturnsEmpty(IssueQuery.builder().issueKeys(asList("I3", "I4")));
  67. }
  68. @Test
  69. public void filter_by_projects() {
  70. ComponentDto project = newPrivateProjectDto();
  71. indexIssues(
  72. newDocForProject("I1", project),
  73. newDoc("I2", project.uuid(), newFileDto(project)));
  74. assertThatSearchReturnsOnly(IssueQuery.builder().projectUuids(singletonList(project.uuid())), "I1", "I2");
  75. assertThatSearchReturnsEmpty(IssueQuery.builder().projectUuids(singletonList("unknown")));
  76. }
  77. @Test
  78. public void filter_by_components_on_contextualized_search() {
  79. ComponentDto project = newPrivateProjectDto();
  80. ComponentDto file1 = newFileDto(project);
  81. String view = "ABCD";
  82. indexView(view, singletonList(project.uuid()));
  83. indexIssues(
  84. newDocForProject("I1", project),
  85. newDoc("I2", project.uuid(), file1));
  86. assertThatSearchReturnsOnly(IssueQuery.builder().files(asList(file1.path())), "I2");
  87. assertThatSearchReturnsOnly(IssueQuery.builder().files(singletonList(file1.path())), "I2");
  88. assertThatSearchReturnsOnly(IssueQuery.builder().projectUuids(singletonList(project.uuid())), "I1", "I2");
  89. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(view)), "I1", "I2");
  90. assertThatSearchReturnsEmpty(IssueQuery.builder().projectUuids(singletonList("unknown")));
  91. }
  92. @Test
  93. public void filter_by_components_on_non_contextualized_search() {
  94. ComponentDto project = newPrivateProjectDto("project");
  95. ComponentDto file1 = newFileDto(project, null, "file1");
  96. String view = "ABCD";
  97. indexView(view, singletonList(project.uuid()));
  98. indexIssues(
  99. newDocForProject("I1", project),
  100. newDoc("I2", project.uuid(), file1));
  101. assertThatSearchReturnsEmpty(IssueQuery.builder().projectUuids(singletonList("unknown")));
  102. assertThatSearchReturnsOnly(IssueQuery.builder().projectUuids(singletonList(project.uuid())), "I1", "I2");
  103. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(view)), "I1", "I2");
  104. assertThatSearchReturnsOnly(IssueQuery.builder().files(singletonList(file1.path())), "I2");
  105. assertThatSearchReturnsOnly(IssueQuery.builder().files(asList(file1.path())), "I2");
  106. }
  107. @Test
  108. public void filter_by_directories() {
  109. ComponentDto project = newPrivateProjectDto();
  110. ComponentDto file1 = newFileDto(project).setPath("src/main/xoo/F1.xoo");
  111. ComponentDto file2 = newFileDto(project).setPath("F2.xoo");
  112. indexIssues(
  113. newDoc("I1", project.uuid(), file1).setDirectoryPath("/src/main/xoo"),
  114. newDoc("I2", project.uuid(), file2).setDirectoryPath("/"));
  115. assertThatSearchReturnsOnly(IssueQuery.builder().directories(singletonList("/src/main/xoo")), "I1");
  116. assertThatSearchReturnsOnly(IssueQuery.builder().directories(singletonList("/")), "I2");
  117. assertThatSearchReturnsEmpty(IssueQuery.builder().directories(singletonList("unknown")));
  118. }
  119. @Test
  120. public void filter_by_portfolios() {
  121. ComponentDto portfolio1 = db.components().insertPrivateApplication().getMainBranchComponent();
  122. ComponentDto portfolio2 = db.components().insertPrivateApplication().getMainBranchComponent();
  123. ComponentDto project1 = db.components().insertPrivateProject().getMainBranchComponent();
  124. ComponentDto file = db.components().insertComponent(newFileDto(project1));
  125. ComponentDto project2 = db.components().insertPrivateProject().getMainBranchComponent();
  126. IssueDoc issueOnProject1 = newDocForProject(project1);
  127. IssueDoc issueOnFile = newDoc(file, project1.uuid());
  128. IssueDoc issueOnProject2 = newDocForProject(project2);
  129. indexIssues(issueOnProject1, issueOnFile, issueOnProject2);
  130. indexView(portfolio1.uuid(), singletonList(project1.uuid()));
  131. indexView(portfolio2.uuid(), singletonList(project2.uuid()));
  132. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(portfolio1.uuid())), issueOnProject1.key(), issueOnFile.key());
  133. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(portfolio2.uuid())), issueOnProject2.key());
  134. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(asList(portfolio1.uuid(), portfolio2.uuid())), issueOnProject1.key(), issueOnFile.key(), issueOnProject2.key());
  135. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(portfolio1.uuid())).projectUuids(singletonList(project1.uuid())), issueOnProject1.key(),
  136. issueOnFile.key());
  137. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(portfolio1.uuid())).files(singletonList(file.path())), issueOnFile.key());
  138. assertThatSearchReturnsEmpty(IssueQuery.builder().viewUuids(singletonList("unknown")));
  139. }
  140. @Test
  141. public void filter_by_portfolios_not_having_projects() {
  142. ComponentDto project1 = newPrivateProjectDto();
  143. ComponentDto file1 = newFileDto(project1);
  144. indexIssues(newDoc("I2", project1.uuid(), file1));
  145. String view1 = "ABCD";
  146. indexView(view1, emptyList());
  147. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(view1)));
  148. }
  149. @Test
  150. public void do_not_return_issues_from_project_branch_when_filtering_by_portfolios() {
  151. ComponentDto portfolio = db.components().insertPrivateApplication().getMainBranchComponent();
  152. ComponentDto project = db.components().insertPublicProject().getMainBranchComponent();
  153. ComponentDto projectBranch = db.components().insertProjectBranch(project);
  154. ComponentDto fileOnProjectBranch = db.components().insertComponent(newFileDto(projectBranch));
  155. indexView(portfolio.uuid(), singletonList(project.uuid()));
  156. IssueDoc issueOnProject = newDocForProject(project);
  157. IssueDoc issueOnProjectBranch = newDoc(projectBranch, project.uuid());
  158. IssueDoc issueOnFileOnProjectBranch = newDoc(fileOnProjectBranch, projectBranch.uuid());
  159. indexIssues(issueOnProject, issueOnFileOnProjectBranch, issueOnProjectBranch);
  160. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(portfolio.uuid())), issueOnProject.key());
  161. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(portfolio.uuid())).projectUuids(singletonList(project.uuid())),
  162. issueOnProject.key());
  163. assertThatSearchReturnsEmpty(IssueQuery.builder().viewUuids(singletonList(portfolio.uuid())).projectUuids(singletonList(projectBranch.uuid())));
  164. }
  165. @Test
  166. public void filter_one_issue_by_project_and_branch() {
  167. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  168. ComponentDto branch = db.components().insertProjectBranch(project);
  169. ComponentDto anotherbBranch = db.components().insertProjectBranch(project);
  170. IssueDoc issueOnProject = newDocForProject(project);
  171. IssueDoc issueOnBranch = newDoc(branch, project.uuid());
  172. IssueDoc issueOnAnotherBranch = newDoc(anotherbBranch, project.uuid());
  173. indexIssues(issueOnProject, issueOnBranch, issueOnAnotherBranch);
  174. assertThatSearchReturnsOnly(IssueQuery.builder().branchUuid(branch.uuid()).mainBranch(false), issueOnBranch.key());
  175. assertThatSearchReturnsOnly(IssueQuery.builder().componentUuids(singletonList(branch.uuid())).branchUuid(branch.uuid()).mainBranch(false), issueOnBranch.key());
  176. assertThatSearchReturnsOnly(IssueQuery.builder().projectUuids(singletonList(project.uuid())).branchUuid(branch.uuid()).mainBranch(false), issueOnBranch.key());
  177. assertThatSearchReturnsOnly(
  178. IssueQuery.builder().componentUuids(singletonList(branch.uuid())).projectUuids(singletonList(project.uuid())).branchUuid(branch.uuid()).mainBranch(false),
  179. issueOnBranch.key());
  180. assertThatSearchReturnsOnly(IssueQuery.builder().projectUuids(singletonList(project.uuid())).mainBranch(null), issueOnProject.key(), issueOnBranch.key(),
  181. issueOnAnotherBranch.key());
  182. assertThatSearchReturnsEmpty(IssueQuery.builder().branchUuid("unknown"));
  183. }
  184. @Test
  185. public void issues_from_branch_component_children() {
  186. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  187. ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
  188. ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
  189. ComponentDto branchFile = db.components().insertComponent(newFileDto(branch, project.uuid()));
  190. indexIssues(
  191. newDocForProject("I1", project),
  192. newDoc("I2", project.uuid(), projectFile),
  193. newDoc("I3", project.uuid(), branch),
  194. newDoc("I4", project.uuid(), branchFile));
  195. assertThatSearchReturnsOnly(IssueQuery.builder().branchUuid(branch.uuid()).mainBranch(false), "I3", "I4");
  196. assertThatSearchReturnsOnly(IssueQuery.builder().files(singletonList(branchFile.path())).branchUuid(branch.uuid()).mainBranch(false), "I4");
  197. assertThatSearchReturnsEmpty(IssueQuery.builder().files(singletonList(branchFile.uuid())).mainBranch(false).branchUuid("unknown"));
  198. }
  199. @Test
  200. public void issues_from_main_branch() {
  201. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  202. ComponentDto branch = db.components().insertProjectBranch(project);
  203. IssueDoc issueOnProject = newDocForProject(project);
  204. IssueDoc issueOnBranch = newDoc(branch, project.uuid());
  205. indexIssues(issueOnProject, issueOnBranch);
  206. assertThatSearchReturnsOnly(IssueQuery.builder().branchUuid(project.uuid()).mainBranch(true), issueOnProject.key());
  207. assertThatSearchReturnsOnly(IssueQuery.builder().componentUuids(singletonList(project.uuid())).branchUuid(project.uuid()).mainBranch(true), issueOnProject.key());
  208. assertThatSearchReturnsOnly(IssueQuery.builder().projectUuids(singletonList(project.uuid())).branchUuid(project.uuid()).mainBranch(true), issueOnProject.key());
  209. assertThatSearchReturnsOnly(
  210. IssueQuery.builder().componentUuids(singletonList(project.uuid())).projectUuids(singletonList(project.uuid())).branchUuid(project.uuid()).mainBranch(true),
  211. issueOnProject.key());
  212. }
  213. @Test
  214. public void branch_issues_are_ignored_when_no_branch_param() {
  215. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  216. ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
  217. IssueDoc projectIssue = newDocForProject(project);
  218. IssueDoc branchIssue = newDoc(branch, project.uuid());
  219. indexIssues(projectIssue, branchIssue);
  220. assertThatSearchReturnsOnly(IssueQuery.builder(), projectIssue.key());
  221. }
  222. @Test
  223. public void filter_by_main_application() {
  224. ComponentDto application1 = db.components().insertPrivateApplication().getMainBranchComponent();
  225. ComponentDto application2 = db.components().insertPrivateApplication().getMainBranchComponent();
  226. ComponentDto project1 = db.components().insertPrivateProject().getMainBranchComponent();
  227. ComponentDto file = db.components().insertComponent(newFileDto(project1));
  228. ComponentDto project2 = db.components().insertPrivateProject().getMainBranchComponent();
  229. indexView(application1.uuid(), singletonList(project1.uuid()));
  230. indexView(application2.uuid(), singletonList(project2.uuid()));
  231. IssueDoc issueOnProject1 = newDocForProject(project1);
  232. IssueDoc issueOnFile = newDoc(file, project1.uuid());
  233. IssueDoc issueOnProject2 = newDocForProject(project2);
  234. indexIssues(issueOnProject1, issueOnFile, issueOnProject2);
  235. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(application1.uuid())), issueOnProject1.key(), issueOnFile.key());
  236. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(application2.uuid())), issueOnProject2.key());
  237. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(asList(application1.uuid(), application2.uuid())), issueOnProject1.key(), issueOnFile.key(), issueOnProject2.key());
  238. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(application1.uuid())).projectUuids(singletonList(project1.uuid())), issueOnProject1.key(),
  239. issueOnFile.key());
  240. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(application1.uuid())).files(singletonList(file.path())), issueOnFile.key());
  241. assertThatSearchReturnsEmpty(IssueQuery.builder().viewUuids(singletonList("unknown")));
  242. }
  243. @Test
  244. public void filter_by_application_branch() {
  245. ComponentDto application = db.components().insertPublicProject(c -> c.setQualifier(APP)).getMainBranchComponent();
  246. ComponentDto branch1 = db.components().insertProjectBranch(application);
  247. ComponentDto branch2 = db.components().insertProjectBranch(application);
  248. ComponentDto project1 = db.components().insertPrivateProject().getMainBranchComponent();
  249. ComponentDto file = db.components().insertComponent(newFileDto(project1));
  250. ComponentDto project2 = db.components().insertPrivateProject().getMainBranchComponent();
  251. indexView(branch1.uuid(), singletonList(project1.uuid()));
  252. indexView(branch2.uuid(), singletonList(project2.uuid()));
  253. IssueDoc issueOnProject1 = newDocForProject(project1);
  254. IssueDoc issueOnFile = newDoc(file, project1.uuid());
  255. IssueDoc issueOnProject2 = newDocForProject(project2);
  256. indexIssues(issueOnProject1, issueOnFile, issueOnProject2);
  257. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(branch1.uuid())).branchUuid(branch1.uuid()).mainBranch(false),
  258. issueOnProject1.key(), issueOnFile.key());
  259. assertThatSearchReturnsOnly(
  260. IssueQuery.builder().viewUuids(singletonList(branch1.uuid())).projectUuids(singletonList(project1.uuid())).branchUuid(branch1.uuid()).mainBranch(false),
  261. issueOnProject1.key(), issueOnFile.key());
  262. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(branch1.uuid())).files(singletonList(file.path())).branchUuid(branch1.uuid()).mainBranch(false),
  263. issueOnFile.key());
  264. assertThatSearchReturnsEmpty(IssueQuery.builder().branchUuid("unknown"));
  265. }
  266. @Test
  267. public void filter_by_application_branch_having_project_branches() {
  268. ComponentDto application = db.components().insertPublicProject(c -> c.setQualifier(APP).setKey("app")).getMainBranchComponent();
  269. ComponentDto applicationBranch1 = db.components().insertProjectBranch(application, a -> a.setKey("app-branch1"));
  270. ComponentDto applicationBranch2 = db.components().insertProjectBranch(application, a -> a.setKey("app-branch2"));
  271. ComponentDto project1 = db.components().insertPrivateProject(p -> p.setKey("prj1")).getMainBranchComponent();
  272. ComponentDto project1Branch1 = db.components().insertProjectBranch(project1);
  273. ComponentDto fileOnProject1Branch1 = db.components().insertComponent(newFileDto(project1Branch1));
  274. ComponentDto project1Branch2 = db.components().insertProjectBranch(project1);
  275. ComponentDto project2 = db.components().insertPrivateProject(p -> p.setKey("prj2")).getMainBranchComponent();
  276. indexView(applicationBranch1.uuid(), asList(project1Branch1.uuid(), project2.uuid()));
  277. indexView(applicationBranch2.uuid(), singletonList(project1Branch2.uuid()));
  278. IssueDoc issueOnProject1 = newDocForProject(project1);
  279. IssueDoc issueOnProject1Branch1 = newDoc(project1Branch1, project1.uuid());
  280. IssueDoc issueOnFileOnProject1Branch1 = newDoc(fileOnProject1Branch1, project1.uuid());
  281. IssueDoc issueOnProject1Branch2 = newDoc(project1Branch2, project1.uuid());
  282. IssueDoc issueOnProject2 = newDocForProject(project2);
  283. indexIssues(issueOnProject1, issueOnProject1Branch1, issueOnFileOnProject1Branch1, issueOnProject1Branch2, issueOnProject2);
  284. assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(applicationBranch1.uuid())).branchUuid(applicationBranch1.uuid()).mainBranch(false),
  285. issueOnProject1Branch1.key(), issueOnFileOnProject1Branch1.key(), issueOnProject2.key());
  286. assertThatSearchReturnsOnly(
  287. IssueQuery.builder().viewUuids(singletonList(applicationBranch1.uuid())).projectUuids(singletonList(project1.uuid())).branchUuid(applicationBranch1.uuid()).mainBranch(false),
  288. issueOnProject1Branch1.key(), issueOnFileOnProject1Branch1.key());
  289. assertThatSearchReturnsOnly(
  290. IssueQuery.builder().viewUuids(singletonList(applicationBranch1.uuid())).files(singletonList(fileOnProject1Branch1.path())).branchUuid(applicationBranch1.uuid())
  291. .mainBranch(false),
  292. issueOnFileOnProject1Branch1.key());
  293. assertThatSearchReturnsEmpty(
  294. IssueQuery.builder().viewUuids(singletonList(applicationBranch1.uuid())).projectUuids(singletonList("unknown")).branchUuid(applicationBranch1.uuid()).mainBranch(false));
  295. }
  296. @Test
  297. public void filter_by_created_after_by_projects() {
  298. Date now = new Date();
  299. ComponentDto project1 = newPrivateProjectDto();
  300. IssueDoc project1Issue1 = newDocForProject(project1).setFuncCreationDate(addDays(now, -10));
  301. IssueDoc project1Issue2 = newDocForProject(project1).setFuncCreationDate(addDays(now, -20));
  302. ComponentDto project2 = newPrivateProjectDto();
  303. IssueDoc project2Issue1 = newDocForProject(project2).setFuncCreationDate(addDays(now, -15));
  304. IssueDoc project2Issue2 = newDocForProject(project2).setFuncCreationDate(addDays(now, -30));
  305. indexIssues(project1Issue1, project1Issue2, project2Issue1, project2Issue2);
  306. // Search for issues of project 1 having less than 15 days
  307. assertThatSearchReturnsOnly(IssueQuery.builder()
  308. .createdAfterByProjectUuids(Map.of(project1.uuid(), new IssueQuery.PeriodStart(addDays(now, -15), true))),
  309. project1Issue1.key());
  310. // Search for issues of project 1 having less than 14 days and project 2 having less then 25 days
  311. assertThatSearchReturnsOnly(IssueQuery.builder()
  312. .createdAfterByProjectUuids(Map.of(
  313. project1.uuid(), new IssueQuery.PeriodStart(addDays(now, -14), true),
  314. project2.uuid(), new IssueQuery.PeriodStart(addDays(now, -25), true))),
  315. project1Issue1.key(), project2Issue1.key());
  316. // Search for issues of project 1 having less than 30 days
  317. assertThatSearchReturnsOnly(IssueQuery.builder()
  318. .createdAfterByProjectUuids(Map.of(
  319. project1.uuid(), new IssueQuery.PeriodStart(addDays(now, -30), true))),
  320. project1Issue1.key(), project1Issue2.key());
  321. // Search for issues of project 1 and project 2 having less than 5 days
  322. assertThatSearchReturnsOnly(IssueQuery.builder()
  323. .createdAfterByProjectUuids(Map.of(
  324. project1.uuid(), new IssueQuery.PeriodStart(addDays(now, -5), true),
  325. project2.uuid(), new IssueQuery.PeriodStart(addDays(now, -5), true))));
  326. }
  327. @Test
  328. public void filter_by_created_after_by_project_branches() {
  329. Date now = new Date();
  330. ComponentDto project1 = db.components().insertPrivateProject().getMainBranchComponent();
  331. IssueDoc project1Issue1 = newDocForProject(project1).setFuncCreationDate(addDays(now, -10));
  332. IssueDoc project1Issue2 = newDocForProject(project1).setFuncCreationDate(addDays(now, -20));
  333. ComponentDto project1Branch1 = db.components().insertProjectBranch(project1);
  334. IssueDoc project1Branch1Issue1 = newDoc(project1Branch1, project1.uuid()).setFuncCreationDate(addDays(now, -10));
  335. IssueDoc project1Branch1Issue2 = newDoc(project1Branch1, project1.uuid()).setFuncCreationDate(addDays(now, -20));
  336. ComponentDto project2 = db.components().insertPrivateProject().getMainBranchComponent();
  337. IssueDoc project2Issue1 = newDocForProject(project2).setFuncCreationDate(addDays(now, -15));
  338. IssueDoc project2Issue2 = newDocForProject(project2).setFuncCreationDate(addDays(now, -30));
  339. ComponentDto project2Branch1 = db.components().insertProjectBranch(project2);
  340. IssueDoc project2Branch1Issue1 = newDoc(project2Branch1, project2.uuid()).setFuncCreationDate(addDays(now, -15));
  341. IssueDoc project2Branch1Issue2 = newDoc(project2Branch1, project2.uuid()).setFuncCreationDate(addDays(now, -30));
  342. indexIssues(project1Issue1, project1Issue2, project2Issue1, project2Issue2,
  343. project1Branch1Issue1, project1Branch1Issue2, project2Branch1Issue1, project2Branch1Issue2);
  344. // Search for issues of project 1 branch 1 having less than 15 days
  345. assertThatSearchReturnsOnly(IssueQuery.builder()
  346. .mainBranch(false)
  347. .createdAfterByProjectUuids(Map.of(project1Branch1.uuid(), new IssueQuery.PeriodStart(addDays(now, -15), true))),
  348. project1Branch1Issue1.key());
  349. // Search for issues of project 1 branch 1 having less than 14 days and project 2 branch 1 having less then 25 days
  350. assertThatSearchReturnsOnly(IssueQuery.builder()
  351. .mainBranch(false)
  352. .createdAfterByProjectUuids(Map.of(
  353. project1Branch1.uuid(), new IssueQuery.PeriodStart(addDays(now, -14), true),
  354. project2Branch1.uuid(), new IssueQuery.PeriodStart(addDays(now, -25), true))),
  355. project1Branch1Issue1.key(), project2Branch1Issue1.key());
  356. // Search for issues of project 1 branch 1 having less than 30 days
  357. assertThatSearchReturnsOnly(IssueQuery.builder()
  358. .mainBranch(false)
  359. .createdAfterByProjectUuids(Map.of(
  360. project1Branch1.uuid(), new IssueQuery.PeriodStart(addDays(now, -30), true))),
  361. project1Branch1Issue1.key(), project1Branch1Issue2.key());
  362. // Search for issues of project 1 branch 1 and project 2 branch 2 having less than 5 days
  363. assertThatSearchReturnsOnly(IssueQuery.builder()
  364. .mainBranch(false)
  365. .createdAfterByProjectUuids(Map.of(
  366. project1Branch1.uuid(), new IssueQuery.PeriodStart(addDays(now, -5), true),
  367. project2Branch1.uuid(), new IssueQuery.PeriodStart(addDays(now, -5), true))));
  368. }
  369. @Test
  370. public void filter_by_new_code_reference_by_projects() {
  371. ComponentDto project1 = newPrivateProjectDto();
  372. IssueDoc project1Issue1 = newDocForProject(project1).setIsNewCodeReference(true);
  373. IssueDoc project1Issue2 = newDocForProject(project1).setIsNewCodeReference(false);
  374. ComponentDto project2 = newPrivateProjectDto();
  375. IssueDoc project2Issue1 = newDocForProject(project2).setIsNewCodeReference(false);
  376. IssueDoc project2Issue2 = newDocForProject(project2).setIsNewCodeReference(true);
  377. indexIssues(project1Issue1, project1Issue2, project2Issue1, project2Issue2);
  378. // Search for issues of project 1 and project 2 that are new code on a branch using reference for new code
  379. assertThatSearchReturnsOnly(IssueQuery.builder()
  380. .newCodeOnReferenceByProjectUuids(Set.of(project1.uuid(), project2.uuid())),
  381. project1Issue1.key(), project2Issue2.key());
  382. }
  383. @Test
  384. public void filter_by_new_code_reference_branches() {
  385. ComponentDto project1 = db.components().insertPrivateProject().getMainBranchComponent();
  386. IssueDoc project1Issue1 = newDocForProject(project1).setIsNewCodeReference(true);
  387. IssueDoc project1Issue2 = newDocForProject(project1).setIsNewCodeReference(false);
  388. ComponentDto project1Branch1 = db.components().insertProjectBranch(project1);
  389. IssueDoc project1Branch1Issue1 = newDoc(project1Branch1, project1.uuid()).setIsNewCodeReference(false);
  390. IssueDoc project1Branch1Issue2 = newDoc(project1Branch1, project1.uuid()).setIsNewCodeReference(true);
  391. ComponentDto project2 = db.components().insertPrivateProject().getMainBranchComponent();
  392. IssueDoc project2Issue1 = newDocForProject(project2).setIsNewCodeReference(true);
  393. IssueDoc project2Issue2 = newDocForProject(project2).setIsNewCodeReference(false);
  394. ComponentDto project2Branch1 = db.components().insertProjectBranch(project2);
  395. IssueDoc project2Branch1Issue1 = newDoc(project2Branch1, project2.uuid()).setIsNewCodeReference(false);
  396. IssueDoc project2Branch1Issue2 = newDoc(project2Branch1, project2.uuid()).setIsNewCodeReference(true);
  397. indexIssues(project1Issue1, project1Issue2, project2Issue1, project2Issue2,
  398. project1Branch1Issue1, project1Branch1Issue2, project2Branch1Issue1, project2Branch1Issue2);
  399. // Search for issues of project 1 branch 1 and project 2 branch 1 that are new code on a branch using reference for new code
  400. assertThatSearchReturnsOnly(IssueQuery.builder()
  401. .mainBranch(false)
  402. .newCodeOnReferenceByProjectUuids(Set.of(project1Branch1.uuid(), project2Branch1.uuid())),
  403. project1Branch1Issue2.key(), project2Branch1Issue2.key());
  404. }
  405. @Test
  406. public void filter_by_severities() {
  407. ComponentDto project = newPrivateProjectDto();
  408. ComponentDto file = newFileDto(project);
  409. indexIssues(
  410. newDoc("I1", project.uuid(), file).setSeverity(Severity.INFO),
  411. newDoc("I2", project.uuid(), file).setSeverity(Severity.MAJOR));
  412. assertThatSearchReturnsOnly(IssueQuery.builder().severities(asList(Severity.INFO, Severity.MAJOR)), "I1", "I2");
  413. assertThatSearchReturnsOnly(IssueQuery.builder().severities(singletonList(Severity.INFO)), "I1");
  414. assertThatSearchReturnsEmpty(IssueQuery.builder().severities(singletonList(Severity.BLOCKER)));
  415. }
  416. @Test
  417. public void filter_by_statuses() {
  418. ComponentDto project = newPrivateProjectDto();
  419. ComponentDto file = newFileDto(project);
  420. indexIssues(
  421. newDoc("I1", project.uuid(), file).setStatus(Issue.STATUS_CLOSED),
  422. newDoc("I2", project.uuid(), file).setStatus(Issue.STATUS_OPEN));
  423. assertThatSearchReturnsOnly(IssueQuery.builder().statuses(asList(Issue.STATUS_CLOSED, Issue.STATUS_OPEN)), "I1", "I2");
  424. assertThatSearchReturnsOnly(IssueQuery.builder().statuses(singletonList(Issue.STATUS_CLOSED)), "I1");
  425. assertThatSearchReturnsEmpty(IssueQuery.builder().statuses(singletonList(Issue.STATUS_CONFIRMED)));
  426. }
  427. @Test
  428. public void filter_by_resolutions() {
  429. ComponentDto project = newPrivateProjectDto();
  430. ComponentDto file = newFileDto(project);
  431. indexIssues(
  432. newDoc("I1", project.uuid(), file).setResolution(Issue.RESOLUTION_FALSE_POSITIVE),
  433. newDoc("I2", project.uuid(), file).setResolution(Issue.RESOLUTION_FIXED));
  434. assertThatSearchReturnsOnly(IssueQuery.builder().resolutions(asList(Issue.RESOLUTION_FALSE_POSITIVE, Issue.RESOLUTION_FIXED)), "I1", "I2");
  435. assertThatSearchReturnsOnly(IssueQuery.builder().resolutions(singletonList(Issue.RESOLUTION_FALSE_POSITIVE)), "I1");
  436. assertThatSearchReturnsEmpty(IssueQuery.builder().resolutions(singletonList(Issue.RESOLUTION_REMOVED)));
  437. }
  438. @Test
  439. public void filter_by_resolved() {
  440. ComponentDto project = newPrivateProjectDto();
  441. ComponentDto file = newFileDto(project);
  442. indexIssues(
  443. newDoc("I1", project.uuid(), file).setStatus(Issue.STATUS_CLOSED).setResolution(Issue.RESOLUTION_FIXED),
  444. newDoc("I2", project.uuid(), file).setStatus(Issue.STATUS_OPEN).setResolution(null),
  445. newDoc("I3", project.uuid(), file).setStatus(Issue.STATUS_OPEN).setResolution(null));
  446. assertThatSearchReturnsOnly(IssueQuery.builder().resolved(true), "I1");
  447. assertThatSearchReturnsOnly(IssueQuery.builder().resolved(false), "I2", "I3");
  448. assertThatSearchReturnsOnly(IssueQuery.builder().resolved(null), "I1", "I2", "I3");
  449. }
  450. @Test
  451. public void filter_by_rules() {
  452. ComponentDto project = newPrivateProjectDto();
  453. ComponentDto file = newFileDto(project);
  454. RuleDto ruleDefinitionDto = newRule();
  455. db.rules().insert(ruleDefinitionDto);
  456. indexIssues(newDoc("I1", project.uuid(), file).setRuleUuid(ruleDefinitionDto.getUuid()));
  457. assertThatSearchReturnsOnly(IssueQuery.builder().ruleUuids(singletonList(ruleDefinitionDto.getUuid())), "I1");
  458. assertThatSearchReturnsEmpty(IssueQuery.builder().ruleUuids(singletonList("uuid-abc")));
  459. }
  460. @Test
  461. public void filter_by_languages() {
  462. ComponentDto project = newPrivateProjectDto();
  463. ComponentDto file = newFileDto(project);
  464. RuleDto ruleDefinitionDto = newRule();
  465. db.rules().insert(ruleDefinitionDto);
  466. indexIssues(newDoc("I1", project.uuid(), file).setRuleUuid(ruleDefinitionDto.getUuid()).setLanguage("xoo"));
  467. assertThatSearchReturnsOnly(IssueQuery.builder().languages(singletonList("xoo")), "I1");
  468. assertThatSearchReturnsEmpty(IssueQuery.builder().languages(singletonList("unknown")));
  469. }
  470. @Test
  471. public void filter_by_assignees() {
  472. ComponentDto project = newPrivateProjectDto();
  473. ComponentDto file = newFileDto(project);
  474. indexIssues(
  475. newDoc("I1", project.uuid(), file).setAssigneeUuid("steph-uuid"),
  476. newDoc("I2", project.uuid(), file).setAssigneeUuid("marcel-uuid"),
  477. newDoc("I3", project.uuid(), file).setAssigneeUuid(null));
  478. assertThatSearchReturnsOnly(IssueQuery.builder().assigneeUuids(singletonList("steph-uuid")), "I1");
  479. assertThatSearchReturnsOnly(IssueQuery.builder().assigneeUuids(asList("steph-uuid", "marcel-uuid")), "I1", "I2");
  480. assertThatSearchReturnsEmpty(IssueQuery.builder().assigneeUuids(singletonList("unknown")));
  481. }
  482. @Test
  483. public void filter_by_assigned() {
  484. ComponentDto project = newPrivateProjectDto();
  485. ComponentDto file = newFileDto(project);
  486. indexIssues(
  487. newDoc("I1", project.uuid(), file).setAssigneeUuid("steph-uuid"),
  488. newDoc("I2", project.uuid(), file).setAssigneeUuid(null),
  489. newDoc("I3", project.uuid(), file).setAssigneeUuid(null));
  490. assertThatSearchReturnsOnly(IssueQuery.builder().assigned(true), "I1");
  491. assertThatSearchReturnsOnly(IssueQuery.builder().assigned(false), "I2", "I3");
  492. assertThatSearchReturnsOnly(IssueQuery.builder().assigned(null), "I1", "I2", "I3");
  493. }
  494. @Test
  495. public void filter_by_authors() {
  496. ComponentDto project = newPrivateProjectDto();
  497. ComponentDto file = newFileDto(project);
  498. indexIssues(
  499. newDoc("I1", project.uuid(), file).setAuthorLogin("steph"),
  500. newDoc("I2", project.uuid(), file).setAuthorLogin("marcel"),
  501. newDoc("I3", project.uuid(), file).setAssigneeUuid(null));
  502. assertThatSearchReturnsOnly(IssueQuery.builder().authors(singletonList("steph")), "I1");
  503. assertThatSearchReturnsOnly(IssueQuery.builder().authors(asList("steph", "marcel")), "I1", "I2");
  504. assertThatSearchReturnsEmpty(IssueQuery.builder().authors(singletonList("unknown")));
  505. }
  506. @Test
  507. public void filter_by_created_after() {
  508. ComponentDto project = newPrivateProjectDto();
  509. ComponentDto file = newFileDto(project);
  510. indexIssues(
  511. newDoc("I1", project.uuid(), file).setFuncCreationDate(parseDate("2014-09-20")),
  512. newDoc("I2", project.uuid(), file).setFuncCreationDate(parseDate("2014-09-23")));
  513. assertThatSearchReturnsOnly(IssueQuery.builder().createdAfter(parseDate("2014-09-19")), "I1", "I2");
  514. // Lower bound is included
  515. assertThatSearchReturnsOnly(IssueQuery.builder().createdAfter(parseDate("2014-09-20")), "I1", "I2");
  516. assertThatSearchReturnsOnly(IssueQuery.builder().createdAfter(parseDate("2014-09-21")), "I2");
  517. assertThatSearchReturnsEmpty(IssueQuery.builder().createdAfter(parseDate("2014-09-25")));
  518. }
  519. @Test
  520. public void filter_by_created_before() {
  521. ComponentDto project = newPrivateProjectDto();
  522. ComponentDto file = newFileDto(project);
  523. indexIssues(
  524. newDoc("I1", project.uuid(), file).setFuncCreationDate(parseDate("2014-09-20")),
  525. newDoc("I2", project.uuid(), file).setFuncCreationDate(parseDate("2014-09-23")));
  526. assertThatSearchReturnsEmpty(IssueQuery.builder().createdBefore(parseDate("2014-09-19")));
  527. // Upper bound is excluded
  528. assertThatSearchReturnsEmpty(IssueQuery.builder().createdBefore(parseDate("2014-09-20")));
  529. assertThatSearchReturnsOnly(IssueQuery.builder().createdBefore(parseDate("2014-09-21")), "I1");
  530. assertThatSearchReturnsOnly(IssueQuery.builder().createdBefore(parseDate("2014-09-25")), "I1", "I2");
  531. }
  532. @Test
  533. public void filter_by_created_after_and_before() {
  534. ComponentDto project = newPrivateProjectDto();
  535. ComponentDto file = newFileDto(project);
  536. indexIssues(
  537. newDoc("I1", project.uuid(), file).setFuncCreationDate(parseDate("2014-09-20")),
  538. newDoc("I2", project.uuid(), file).setFuncCreationDate(parseDate("2014-09-23")));
  539. // 19 < createdAt < 25
  540. assertThatSearchReturnsOnly(IssueQuery.builder().createdAfter(parseDate("2014-09-19")).createdBefore(parseDate("2014-09-25")),
  541. "I1", "I2");
  542. // 20 < createdAt < 25: excludes first issue
  543. assertThatSearchReturnsOnly(IssueQuery.builder()
  544. .createdAfter(parseDate("2014-09-20")).createdBefore(parseDate("2014-09-25")), "I1", "I2");
  545. // 21 < createdAt < 25
  546. assertThatSearchReturnsOnly(IssueQuery.builder()
  547. .createdAfter(parseDate("2014-09-21")).createdBefore(parseDate("2014-09-25")), "I2");
  548. // 21 < createdAt < 24
  549. assertThatSearchReturnsOnly(IssueQuery.builder()
  550. .createdAfter(parseDate("2014-09-21")).createdBefore(parseDate("2014-09-24")), "I2");
  551. // 21 < createdAt < 23: excludes second issue
  552. assertThatSearchReturnsEmpty(IssueQuery.builder()
  553. .createdAfter(parseDate("2014-09-21")).createdBefore(parseDate("2014-09-23")));
  554. // 19 < createdAt < 21: only first issue
  555. assertThatSearchReturnsOnly(IssueQuery.builder()
  556. .createdAfter(parseDate("2014-09-19")).createdBefore(parseDate("2014-09-21")), "I1");
  557. // 20 < createdAt < 20: exception
  558. assertThatThrownBy(() -> underTest.search(IssueQuery.builder()
  559. .createdAfter(parseDate("2014-09-20")).createdBefore(parseDate("2014-09-20"))
  560. .build(), new SearchOptions()))
  561. .isInstanceOf(IllegalArgumentException.class);
  562. }
  563. @Test
  564. public void filter_by_created_after_and_before_take_into_account_timezone() {
  565. ComponentDto project = newPrivateProjectDto();
  566. ComponentDto file = newFileDto(project);
  567. indexIssues(
  568. newDoc("I1", project.uuid(), file).setFuncCreationDate(parseDateTime("2014-09-20T00:00:00+0100")),
  569. newDoc("I2", project.uuid(), file).setFuncCreationDate(parseDateTime("2014-09-23T00:00:00+0100")));
  570. assertThatSearchReturnsOnly(IssueQuery.builder().createdAfter(parseDateTime("2014-09-19T23:00:00+0000")).createdBefore(parseDateTime("2014-09-22T23:00:01+0000")),
  571. "I1", "I2");
  572. assertThatSearchReturnsEmpty(IssueQuery.builder().createdAfter(parseDateTime("2014-09-19T23:00:01+0000")).createdBefore(parseDateTime("2014-09-22T23:00:00+0000")));
  573. }
  574. @Test
  575. public void filter_by_created_before_must_be_lower_than_after() {
  576. try {
  577. underTest.search(IssueQuery.builder().createdAfter(parseDate("2014-09-20")).createdBefore(parseDate("2014-09-19")).build(),
  578. new SearchOptions());
  579. Fail.failBecauseExceptionWasNotThrown(IllegalArgumentException.class);
  580. } catch (IllegalArgumentException exception) {
  581. assertThat(exception.getMessage()).isEqualTo("Start bound cannot be larger or equal to end bound");
  582. }
  583. }
  584. @Test
  585. public void fail_if_created_before_equals_created_after() {
  586. assertThatThrownBy(() -> underTest.search(IssueQuery.builder().createdAfter(parseDate("2014-09-20"))
  587. .createdBefore(parseDate("2014-09-20")).build(), new SearchOptions()))
  588. .isInstanceOf(IllegalArgumentException.class)
  589. .hasMessageContaining("Start bound cannot be larger or equal to end bound");
  590. }
  591. @Test
  592. public void filter_by_created_after_must_not_be_in_future() {
  593. try {
  594. underTest.search(IssueQuery.builder().createdAfter(new Date(Long.MAX_VALUE)).build(), new SearchOptions());
  595. Fail.failBecauseExceptionWasNotThrown(IllegalArgumentException.class);
  596. } catch (IllegalArgumentException exception) {
  597. assertThat(exception.getMessage()).isEqualTo("Start bound cannot be in the future");
  598. }
  599. }
  600. @Test
  601. public void filter_by_created_at() {
  602. ComponentDto project = newPrivateProjectDto();
  603. ComponentDto file = newFileDto(project);
  604. indexIssues(newDoc("I1", project.uuid(), file).setFuncCreationDate(parseDate("2014-09-20")));
  605. assertThatSearchReturnsOnly(IssueQuery.builder().createdAt(parseDate("2014-09-20")), "I1");
  606. assertThatSearchReturnsEmpty(IssueQuery.builder().createdAt(parseDate("2014-09-21")));
  607. }
  608. @Test
  609. public void filter_by_new_code_reference() {
  610. ComponentDto project = newPrivateProjectDto();
  611. ComponentDto file = newFileDto(project);
  612. indexIssues(newDoc("I1", project.uuid(), file).setIsNewCodeReference(true),
  613. newDoc("I2", project.uuid(), file).setIsNewCodeReference(false));
  614. assertThatSearchReturnsOnly(IssueQuery.builder().newCodeOnReference(true), "I1");
  615. }
  616. @Test
  617. public void filter_by_cwe() {
  618. ComponentDto project = newPrivateProjectDto();
  619. ComponentDto file = newFileDto(project);
  620. indexIssues(
  621. newDoc("I1", project.uuid(), file).setType(RuleType.VULNERABILITY).setCwe(asList("20", "564", "89", "943")),
  622. newDoc("I2", project.uuid(), file).setType(RuleType.VULNERABILITY).setCwe(singletonList("943")),
  623. newDoc("I3", project.uuid(), file));
  624. assertThatSearchReturnsOnly(IssueQuery.builder().cwe(singletonList("20")), "I1");
  625. }
  626. @Test
  627. public void filter_by_owaspAsvs40_category() {
  628. ComponentDto project = newPrivateProjectDto();
  629. ComponentDto file = newFileDto(project);
  630. indexIssues(
  631. newDoc("I1", project.uuid(), file).setType(RuleType.VULNERABILITY).setOwaspAsvs40(asList("1.1.1", "1.2.2", "2.2.2")),
  632. newDoc("I2", project.uuid(), file).setType(RuleType.VULNERABILITY).setOwaspAsvs40(asList("1.1.1", "1.2.2")),
  633. newDoc("I3", project.uuid(), file));
  634. assertThatSearchReturnsOnly(IssueQuery.builder().owaspAsvs40(singletonList("1")), "I1", "I2");
  635. assertThatSearchReturnsOnly(IssueQuery.builder().owaspAsvs40(singletonList("2")), "I1");
  636. assertThatSearchReturnsOnly(IssueQuery.builder().owaspAsvs40(singletonList("3")));
  637. }
  638. @Test
  639. public void filter_by_owaspAsvs40_specific_requirement() {
  640. ComponentDto project = newPrivateProjectDto();
  641. ComponentDto file = newFileDto(project);
  642. indexIssues(
  643. newDoc("I1", project.uuid(), file).setType(RuleType.VULNERABILITY).setOwaspAsvs40(asList("1.1.1", "1.2.2", "2.2.2")),
  644. newDoc("I2", project.uuid(), file).setType(RuleType.VULNERABILITY).setOwaspAsvs40(asList("1.1.1", "1.2.2")),
  645. newDoc("I3", project.uuid(), file));
  646. assertThatSearchReturnsOnly(IssueQuery.builder().owaspAsvs40(singletonList("1.1.1")), "I1", "I2");
  647. assertThatSearchReturnsOnly(IssueQuery.builder().owaspAsvs40(singletonList("2.2.2")), "I1");
  648. assertThatSearchReturnsOnly(IssueQuery.builder().owaspAsvs40(singletonList("3.3.3")));
  649. }
  650. @Test
  651. public void filter_by_owaspAsvs40_level() {
  652. ComponentDto project = newPrivateProjectDto();
  653. ComponentDto file = newFileDto(project);
  654. indexIssues(
  655. newDoc("I1", project.uuid(), file).setType(RuleType.VULNERABILITY).setOwaspAsvs40(asList("2.1.1", "1.1.1", "1.11.3")),
  656. newDoc("I2", project.uuid(), file).setType(RuleType.VULNERABILITY).setOwaspAsvs40(asList("1.1.1", "1.11.3")),
  657. newDoc("I3", project.uuid(), file).setType(RuleType.VULNERABILITY).setOwaspAsvs40(singletonList("1.11.3")),
  658. newDoc("IError1", project.uuid(), file).setType(RuleType.VULNERABILITY).setOwaspAsvs40(asList("5.5.1", "7.2.2", "10.2.6")),
  659. newDoc("IError2", project.uuid(), file));
  660. assertThatSearchReturnsOnly(
  661. IssueQuery.builder().owaspAsvs40(singletonList("1.1.1")).owaspAsvsLevel(1));
  662. assertThatSearchReturnsOnly(
  663. IssueQuery.builder().owaspAsvs40(singletonList("1.1.1")).owaspAsvsLevel(2),
  664. "I1", "I2");
  665. assertThatSearchReturnsOnly(
  666. IssueQuery.builder().owaspAsvs40(singletonList("1.1.1")).owaspAsvsLevel(3),
  667. "I1", "I2");
  668. }
  669. @Test
  670. public void filter_by_owaspTop10() {
  671. ComponentDto project = newPrivateProjectDto();
  672. ComponentDto file = newFileDto(project);
  673. indexIssues(
  674. newDoc("I1", project.uuid(), file).setType(RuleType.VULNERABILITY).setOwaspTop10(asList("a1", "a2")),
  675. newDoc("I2", project.uuid(), file).setType(RuleType.VULNERABILITY).setCwe(singletonList("a3")),
  676. newDoc("I3", project.uuid(), file));
  677. assertThatSearchReturnsOnly(IssueQuery.builder().owaspTop10(singletonList("a1")), "I1");
  678. }
  679. @Test
  680. public void filter_by_sansTop25() {
  681. ComponentDto project = newPrivateProjectDto();
  682. ComponentDto file = newFileDto(project);
  683. indexIssues(
  684. newDoc("I1", project.uuid(), file).setType(RuleType.VULNERABILITY).setSansTop25(asList("porous-defenses", "risky-resource", "insecure-interaction")),
  685. newDoc("I2", project.uuid(), file).setType(RuleType.VULNERABILITY).setSansTop25(singletonList("porous-defenses")),
  686. newDoc("I3", project.uuid(), file));
  687. assertThatSearchReturnsOnly(IssueQuery.builder().sansTop25(singletonList("risky-resource")), "I1");
  688. }
  689. @Test
  690. public void filter_by_sonarSecurity() {
  691. ComponentDto project = newPrivateProjectDto();
  692. ComponentDto file = newFileDto(project);
  693. indexIssues(
  694. newDoc("I1", project.uuid(), file).setType(RuleType.VULNERABILITY).setSonarSourceSecurityCategory(SQCategory.BUFFER_OVERFLOW),
  695. newDoc("I2", project.uuid(), file).setType(RuleType.VULNERABILITY).setSonarSourceSecurityCategory(SQCategory.DOS),
  696. newDoc("I3", project.uuid(), file));
  697. assertThatSearchReturnsOnly(IssueQuery.builder().sonarsourceSecurity(singletonList("buffer-overflow")), "I1");
  698. }
  699. @Test
  700. public void search_whenFilteringByCodeVariants_shouldReturnRelevantIssues() {
  701. ComponentDto project = newPrivateProjectDto();
  702. ComponentDto file = newFileDto(project);
  703. indexIssues(
  704. newDoc("I1", project.uuid(), file).setCodeVariants(asList("variant1", "variant2")),
  705. newDoc("I2", project.uuid(), file).setCodeVariants(singletonList("variant2")),
  706. newDoc("I3", project.uuid(), file).setCodeVariants(singletonList("variant3")),
  707. newDoc("I4", project.uuid(), file));
  708. assertThatSearchReturnsOnly(IssueQuery.builder().codeVariants(singletonList("variant2")), "I1", "I2");
  709. }
  710. @Test
  711. public void search_whenFilteringBySoftwareQualities_shouldReturnRelevantIssues() {
  712. ComponentDto project = newPrivateProjectDto();
  713. ComponentDto file = newFileDto(project);
  714. indexIssues(
  715. newDoc("I1", project.uuid(), file).setImpacts(Map.of(
  716. MAINTAINABILITY, org.sonar.api.issue.impact.Severity.HIGH,
  717. SECURITY, org.sonar.api.issue.impact.Severity.LOW,
  718. RELIABILITY, org.sonar.api.issue.impact.Severity.MEDIUM)),
  719. newDoc("I2", project.uuid(), file).setImpacts(Map.of(
  720. MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW,
  721. SECURITY, org.sonar.api.issue.impact.Severity.LOW)),
  722. newDoc("I3", project.uuid(), file).setImpacts(Map.of(
  723. RELIABILITY, org.sonar.api.issue.impact.Severity.HIGH)),
  724. newDoc("I4", project.uuid(), file).setImpacts(Map.of(
  725. MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW)));
  726. assertThatSearchReturnsOnly(IssueQuery.builder().impactSoftwareQualities(Set.of(MAINTAINABILITY.name())),
  727. "I1", "I2", "I4");
  728. assertThatSearchReturnsOnly(IssueQuery.builder().impactSoftwareQualities(Set.of(MAINTAINABILITY.name(), RELIABILITY.name())),
  729. "I1", "I2", "I3", "I4");
  730. assertThatSearchReturnsOnly(IssueQuery.builder().impactSeverities(Set.of(org.sonar.api.issue.impact.Severity.HIGH.name())),
  731. "I1", "I3");
  732. assertThatSearchReturnsOnly(IssueQuery.builder().impactSeverities(Set.of(org.sonar.api.issue.impact.Severity.LOW.name(), org.sonar.api.issue.impact.Severity.MEDIUM.name())),
  733. "I1", "I2", "I4");
  734. assertThatSearchReturnsOnly(IssueQuery.builder()
  735. .impactSoftwareQualities(Set.of(MAINTAINABILITY.name()))
  736. .impactSeverities(Set.of(org.sonar.api.issue.impact.Severity.HIGH.name())),
  737. "I1");
  738. }
  739. @Test
  740. public void search_whenFilteringByCleanCodeAttributeCategory_shouldReturnRelevantIssues() {
  741. ComponentDto project = newPrivateProjectDto();
  742. ComponentDto file = newFileDto(project);
  743. indexIssues(
  744. newDoc("I1", project.uuid(), file).setCleanCodeAttributeCategory(ADAPTABLE.name()),
  745. newDoc("I2", project.uuid(), file).setCleanCodeAttributeCategory(ADAPTABLE.name()),
  746. newDoc("I3", project.uuid(), file).setCleanCodeAttributeCategory(CONSISTENT.name()),
  747. newDoc("I4", project.uuid(), file).setCleanCodeAttributeCategory(INTENTIONAL.name()),
  748. newDoc("I5", project.uuid(), file).setCleanCodeAttributeCategory(INTENTIONAL.name()),
  749. newDoc("I6", project.uuid(), file).setCleanCodeAttributeCategory(INTENTIONAL.name()),
  750. newDoc("I7", project.uuid(), file).setCleanCodeAttributeCategory(INTENTIONAL.name()),
  751. newDoc("I8", project.uuid(), file).setCleanCodeAttributeCategory(RESPONSIBLE.name()));
  752. assertThatSearchReturnsOnly(IssueQuery.builder().cleanCodeAttributesCategories(Set.of(ADAPTABLE.name())),
  753. "I1", "I2");
  754. assertThatSearchReturnsOnly(IssueQuery.builder().cleanCodeAttributesCategories(Set.of(CONSISTENT.name(), INTENTIONAL.name())),
  755. "I3", "I4", "I5", "I6", "I7");
  756. assertThatSearchReturnsOnly(IssueQuery.builder().cleanCodeAttributesCategories(
  757. Set.of(CONSISTENT.name(), INTENTIONAL.name(), RESPONSIBLE.name(), ADAPTABLE.name())),
  758. "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8");
  759. }
  760. @Test
  761. public void search_whenFilteringBySimpleStatus_shouldReturnRelevantIssues() {
  762. ComponentDto project = newPrivateProjectDto();
  763. ComponentDto file = newFileDto(project);
  764. indexIssues(
  765. newDoc("I1", project.uuid(), file).setSimpleStatus(SimpleStatus.CONFIRMED.name()),
  766. newDoc("I2", project.uuid(), file).setSimpleStatus(SimpleStatus.FIXED.name()),
  767. newDoc("I3", project.uuid(), file).setSimpleStatus(SimpleStatus.OPEN.name()),
  768. newDoc("I4", project.uuid(), file).setSimpleStatus(SimpleStatus.OPEN.name()),
  769. newDoc("I5", project.uuid(), file).setSimpleStatus(SimpleStatus.ACCEPTED.name()),
  770. newDoc("I6", project.uuid(), file).setSimpleStatus(SimpleStatus.ACCEPTED.name()),
  771. newDoc("I7", project.uuid(), file).setSimpleStatus(SimpleStatus.ACCEPTED.name()),
  772. newDoc("I8", project.uuid(), file).setSimpleStatus(SimpleStatus.FALSE_POSITIVE.name()),
  773. newDoc("I9", project.uuid(), file).setSimpleStatus(SimpleStatus.FALSE_POSITIVE.name()));
  774. assertThatSearchReturnsOnly(IssueQuery.builder().simpleStatuses(Set.of(SimpleStatus.CONFIRMED.name(), SimpleStatus.OPEN.name())),
  775. "I1", "I3", "I4");
  776. assertThatSearchReturnsOnly(IssueQuery.builder().simpleStatuses(Set.of(SimpleStatus.FALSE_POSITIVE.name(), SimpleStatus.ACCEPTED.name())),
  777. "I5", "I6", "I7", "I8", "I9");
  778. assertThatSearchReturnsOnly(IssueQuery.builder().simpleStatuses(Set.of(SimpleStatus.FIXED.name())),
  779. "I2");
  780. }
  781. private void indexView(String viewUuid, List<String> projectBranchUuids) {
  782. viewIndexer.index(new ViewDoc().setUuid(viewUuid).setProjectBranchUuids(projectBranchUuids));
  783. }
  784. }