3 * Copyright (C) 2009-2020 SonarSource SA
4 * mailto:info AT sonarsource DOT com
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.
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.
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.
20 package org.sonar.server.issue.ws;
22 import java.time.Clock;
23 import java.util.Arrays;
24 import java.util.Date;
25 import org.junit.Rule;
26 import org.junit.Test;
27 import org.junit.rules.ExpectedException;
28 import org.sonar.api.resources.Languages;
29 import org.sonar.api.resources.Qualifiers;
30 import org.sonar.api.rule.RuleKey;
31 import org.sonar.api.utils.Durations;
32 import org.sonar.api.utils.System2;
33 import org.sonar.db.DbClient;
34 import org.sonar.db.DbTester;
35 import org.sonar.db.component.ComponentDto;
36 import org.sonar.db.issue.IssueDto;
37 import org.sonar.db.organization.OrganizationDto;
38 import org.sonar.db.rule.RuleDefinitionDto;
39 import org.sonar.server.es.EsTester;
40 import org.sonar.server.issue.AvatarResolverImpl;
41 import org.sonar.server.issue.IssueFieldsSetter;
42 import org.sonar.server.issue.TextRangeResponseFormatter;
43 import org.sonar.server.issue.TransitionService;
44 import org.sonar.server.issue.index.IssueIndex;
45 import org.sonar.server.issue.index.IssueIndexer;
46 import org.sonar.server.issue.index.IssueIteratorFactory;
47 import org.sonar.server.issue.index.IssueQueryFactory;
48 import org.sonar.server.issue.workflow.FunctionExecutor;
49 import org.sonar.server.issue.workflow.IssueWorkflow;
50 import org.sonar.server.permission.index.PermissionIndexerTester;
51 import org.sonar.server.permission.index.WebAuthorizationTypeSupport;
52 import org.sonar.server.tester.UserSessionRule;
53 import org.sonar.server.view.index.ViewIndexer;
54 import org.sonar.server.ws.WsActionTester;
55 import org.sonarqube.ws.Issues;
56 import org.sonarqube.ws.Issues.Component;
57 import org.sonarqube.ws.Issues.Issue;
58 import org.sonarqube.ws.Issues.SearchWsResponse;
60 import static org.assertj.core.api.Assertions.assertThat;
61 import static org.assertj.core.api.Assertions.tuple;
62 import static org.sonar.api.resources.Qualifiers.APP;
63 import static org.sonar.api.utils.DateUtils.addDays;
64 import static org.sonar.api.utils.DateUtils.parseDateTime;
65 import static org.sonar.api.web.UserRole.USER;
66 import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
67 import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02;
68 import static org.sonar.db.component.BranchType.BRANCH;
69 import static org.sonar.db.component.BranchType.PULL_REQUEST;
70 import static org.sonar.db.component.ComponentTesting.newDirectory;
71 import static org.sonar.db.component.ComponentTesting.newFileDto;
72 import static org.sonar.db.component.ComponentTesting.newModuleDto;
73 import static org.sonar.db.component.ComponentTesting.newProjectCopy;
74 import static org.sonar.db.component.ComponentTesting.newSubView;
75 import static org.sonar.db.component.ComponentTesting.newView;
76 import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BRANCH;
77 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS;
78 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_UUIDS;
79 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_DIRECTORIES;
80 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_FILE_UUIDS;
81 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_MODULE_UUIDS;
82 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECTS;
83 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECT_KEYS;
84 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PULL_REQUEST;
85 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SINCE_LEAK_PERIOD;
87 public class SearchActionComponentsTest {
90 public ExpectedException expectedException = ExpectedException.none();
92 public UserSessionRule userSession = UserSessionRule.standalone();
94 public DbTester db = DbTester.create();
96 public EsTester es = EsTester.create();
98 private DbClient dbClient = db.getDbClient();
99 private IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession, new WebAuthorizationTypeSupport(userSession));
100 private IssueIndexer issueIndexer = new IssueIndexer(es.client(), dbClient, new IssueIteratorFactory(dbClient), null);
101 private ViewIndexer viewIndexer = new ViewIndexer(dbClient, es.client());
102 private IssueQueryFactory issueQueryFactory = new IssueQueryFactory(dbClient, Clock.systemUTC(), userSession);
103 private IssueFieldsSetter issueFieldsSetter = new IssueFieldsSetter();
104 private IssueWorkflow issueWorkflow = new IssueWorkflow(new FunctionExecutor(issueFieldsSetter), issueFieldsSetter);
105 private SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSession, dbClient, new TransitionService(userSession, issueWorkflow));
106 private Languages languages = new Languages();
107 private UserResponseFormatter userFormatter = new UserResponseFormatter(new AvatarResolverImpl());
108 private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new TextRangeResponseFormatter(), userFormatter);
109 private PermissionIndexerTester permissionIndexer = new PermissionIndexerTester(es, issueIndexer);
111 private WsActionTester ws = new WsActionTester(new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat,
112 System2.INSTANCE, dbClient));
115 public void search_all_issues_when_no_parameter() {
116 RuleDefinitionDto rule = db.rules().insertIssueRule();
117 ComponentDto project = db.components().insertPublicProject();
118 ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
119 IssueDto issue = db.issues().insertIssue(rule, project, projectFile);
120 allowAnyoneOnProjects(project);
123 SearchWsResponse result = ws.newRequest().executeProtobuf(SearchWsResponse.class);
125 assertThat(result.getIssuesList()).extracting(Issues.Issue::getKey)
126 .containsExactlyInAnyOrder(issue.getKey());
130 public void issues_on_different_projects() {
131 RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
132 OrganizationDto organization1 = db.organizations().insert();
133 ComponentDto project = db.components().insertPublicProject(organization1);
134 ComponentDto file = db.components().insertComponent(newFileDto(project));
135 IssueDto issue1 = db.issues().insertIssue(rule, project, file);
136 OrganizationDto organization2 = db.organizations().insert();
137 ComponentDto project2 = db.components().insertPublicProject(organization2);
138 ComponentDto file2 = db.components().insertComponent(newFileDto(project2));
139 IssueDto issue2 = db.issues().insertIssue(rule, project2, file2);
140 allowAnyoneOnProjects(project, project2);
143 SearchWsResponse response = ws.newRequest().executeProtobuf(SearchWsResponse.class);
145 assertThat(response.getIssuesList())
146 .extracting(Issue::getKey, Issue::getComponent, Issue::getProject)
147 .containsExactlyInAnyOrder(
148 tuple(issue1.getKey(), file.getKey(), project.getKey()),
149 tuple(issue2.getKey(), file2.getKey(), project2.getKey()));
150 assertThat(response.getComponentsList())
151 .extracting(Component::getKey, Component::getEnabled)
152 .containsExactlyInAnyOrder(tuple(project.getKey(), true), tuple(file.getKey(), true), tuple(project2.getKey(), true), tuple(file2.getKey(), true));
156 public void search_by_module() {
157 ComponentDto project = db.components().insertPublicProject();
158 ComponentDto module1 = db.components().insertComponent(newModuleDto(project));
159 ComponentDto file1 = db.components().insertComponent(newFileDto(module1));
160 ComponentDto module2 = db.components().insertComponent(newModuleDto(project));
161 ComponentDto file2 = db.components().insertComponent(newFileDto(module2));
162 RuleDefinitionDto rule = db.rules().insertIssueRule();
163 IssueDto issue1 = db.issues().insertIssue(rule, project, file1);
164 IssueDto issue2 = db.issues().insertIssue(rule, project, file2);
165 allowAnyoneOnProjects(project);
168 assertThat(ws.newRequest()
169 .setParam(PARAM_COMPONENT_KEYS, module1.getKey())
170 .executeProtobuf(SearchWsResponse.class).getIssuesList()).extracting(Issue::getKey)
171 .containsExactlyInAnyOrder(issue1.getKey());
173 assertThat(ws.newRequest()
174 .setParam(PARAM_MODULE_UUIDS, module1.uuid())
175 .executeProtobuf(SearchWsResponse.class).getIssuesList()).extracting(Issue::getKey)
176 .containsExactlyInAnyOrder(issue1.getKey());
180 public void do_not_return_module_key_on_single_module_projects() {
181 ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
182 ComponentDto module = db.components().insertComponent(newModuleDto("M1", project).setDbKey("MK1"));
183 ComponentDto file = db.components().insertComponent(newFileDto(module, null, "F1").setDbKey("FK1"));
184 RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
185 db.issues().insertIssue(rule, project, file, i -> i.setKee("ISSUE_IN_MODULE"));
186 db.issues().insertIssue(rule, project, project, i -> i.setKee("ISSUE_IN_ROOT_MODULE"));
187 allowAnyoneOnProjects(project);
190 SearchWsResponse searchResponse = ws.newRequest().executeProtobuf(SearchWsResponse.class);
191 assertThat(searchResponse.getIssuesCount()).isEqualTo(2);
193 for (Issue issue : searchResponse.getIssuesList()) {
194 assertThat(issue.getProject()).isEqualTo("PK1");
195 if (issue.getKey().equals("ISSUE_IN_MODULE")) {
196 assertThat(issue.getSubProject()).isEqualTo("MK1");
197 } else if (issue.getKey().equals("ISSUE_IN_ROOT_MODULE")) {
198 assertThat(issue.hasSubProject()).isFalse();
204 public void search_since_leak_period_on_project() {
205 ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
206 ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
207 db.components().insertSnapshot(project, a -> a.setPeriodDate(parseDateTime("2015-09-03T00:00:00+0100").getTime()));
208 RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
209 IssueDto issueAfterLeak = db.issues().insertIssue(rule, project, file, i -> i.setKee(UUID_EXAMPLE_01)
210 .setIssueCreationDate(parseDateTime("2015-09-04T00:00:00+0100"))
211 .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100")));
212 IssueDto issueBeforeLeak = db.issues().insertIssue(rule, project, file, i -> i.setKee(UUID_EXAMPLE_02)
213 .setIssueCreationDate(parseDateTime("2014-09-04T00:00:00+0100"))
214 .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100")));
215 allowAnyoneOnProjects(project);
219 .setParam(PARAM_COMPONENT_UUIDS, project.uuid())
220 .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
222 .assertJson(this.getClass(), "search_since_leak_period.json");
226 public void search_since_leak_period_on_file_in_module_project() {
227 ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
228 ComponentDto module = db.components().insertComponent(newModuleDto(project));
229 ComponentDto file = db.components().insertComponent(newFileDto(module, null, "F1").setDbKey("FK1"));
230 db.components().insertSnapshot(project, a -> a.setPeriodDate(parseDateTime("2015-09-03T00:00:00+0100").getTime()));
231 RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
232 IssueDto issueAfterLeak = db.issues().insertIssue(rule, project, file, i -> i.setKee(UUID_EXAMPLE_01)
233 .setIssueCreationDate(parseDateTime("2015-09-04T00:00:00+0100"))
234 .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100")));
235 IssueDto issueBeforeLeak = db.issues().insertIssue(rule, project, file, i -> i.setKee(UUID_EXAMPLE_02)
236 .setIssueCreationDate(parseDateTime("2014-09-04T00:00:00+0100"))
237 .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100")));
238 allowAnyoneOnProjects(project);
242 .setParam(PARAM_COMPONENT_UUIDS, project.uuid())
243 .setParam(PARAM_FILE_UUIDS, file.uuid())
244 .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
246 .assertJson(this.getClass(), "search_since_leak_period.json");
250 public void search_by_file_uuid() {
251 ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
252 ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
253 RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
254 IssueDto issue = db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
255 allowAnyoneOnProjects(project);
259 .setParam(PARAM_FILE_UUIDS, file.uuid())
261 .assertJson(this.getClass(), "search_by_file_uuid.json");
264 .setParam(PARAM_FILE_UUIDS, "unknown")
266 .assertJson(this.getClass(), "no_issue.json");
269 .setParam(PARAM_COMPONENT_UUIDS, file.uuid())
271 .assertJson(this.getClass(), "search_by_file_uuid.json");
274 .setParam(PARAM_COMPONENT_UUIDS, "unknown")
276 .assertJson(this.getClass(), "no_issue.json");
280 public void search_by_file_key() {
281 ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
282 ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
283 ComponentDto unitTest = db.components().insertComponent(newFileDto(project, null, "F2").setQualifier(Qualifiers.UNIT_TEST_FILE).setDbKey("FK2"));
284 RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
285 IssueDto issueOnFile = db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
286 IssueDto issueOnTest = db.issues().insertIssue(rule, project, unitTest, i -> i.setKee("2bd4eac2-b650-4037-80bc-7b1182fd47d4"));
287 allowAnyoneOnProjects(project);
291 .setParam(PARAM_COMPONENT_KEYS, file.getKey())
293 .assertJson(this.getClass(), "search_by_file_key.json");
296 .setParam(PARAM_COMPONENT_KEYS, unitTest.getKey())
298 .assertJson(this.getClass(), "search_by_test_key.json");
302 public void search_by_directory_path() {
303 ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
304 ComponentDto directory = db.components().insertComponent(newDirectory(project, "D1", "src/main/java/dir"));
305 ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1").setPath(directory.path() + "/MyComponent.java"));
306 RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
307 db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
308 allowAnyoneOnProjects(project);
312 .setParam(PARAM_COMPONENT_KEYS, directory.getKey())
314 .assertJson(this.getClass(), "search_by_file_uuid.json");
317 .setParam(PARAM_DIRECTORIES, "unknown")
319 .assertJson(this.getClass(), "no_issue.json");
322 .setParam(PARAM_DIRECTORIES, "src/main/java/dir")
324 .assertJson(this.getClass(), "search_by_file_uuid.json");
327 .setParam(PARAM_DIRECTORIES, "src/main/java")
329 .assertJson(this.getClass(), "no_issue.json");
333 public void search_by_directory_path_in_different_modules() {
334 ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
335 ComponentDto module1 = db.components().insertComponent(newModuleDto("M1", project).setDbKey("MK1"));
336 ComponentDto module2 = db.components().insertComponent(newModuleDto("M2", project).setDbKey("MK2"));
337 ComponentDto directory1 = db.components().insertComponent(newDirectory(module1, "D1", "src/main/java/dir"));
338 ComponentDto directory2 = db.components().insertComponent(newDirectory(module2, "D2", "src/main/java/dir"));
339 ComponentDto file1 = db.components().insertComponent(newFileDto(module1, directory1, "F1").setDbKey("FK1").setPath(directory1.path() + "/MyComponent.java"));
340 db.components().insertComponent(newFileDto(module2, directory2, "F2").setDbKey("FK2").setPath(directory2.path() + "/MyComponent.java"));
341 RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
342 db.issues().insertIssue(rule, project, file1, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
343 allowAnyoneOnProjects(project);
347 .setParam(PARAM_COMPONENT_KEYS, directory1.getKey())
349 .assertJson(this.getClass(), "search_by_directory_uuid.json");
352 .setParam(PARAM_COMPONENT_KEYS, directory2.getKey())
354 .assertJson(this.getClass(), "no_issue.json");
357 .setParam(PARAM_MODULE_UUIDS, module1.uuid())
358 .setParam(PARAM_DIRECTORIES, "src/main/java/dir")
360 .assertJson(this.getClass(), "search_by_directory_uuid.json");
363 .setParam(PARAM_MODULE_UUIDS, module2.uuid())
364 .setParam(PARAM_DIRECTORIES, "src/main/java/dir")
366 .assertJson(this.getClass(), "no_issue.json");
369 .setParam(PARAM_DIRECTORIES, "src/main/java/dir")
371 .assertJson(this.getClass(), "search_by_directory_uuid.json");
374 .setParam(PARAM_DIRECTORIES, "src/main/java")
376 .assertJson(this.getClass(), "no_issue.json");
380 public void search_by_view_uuid() {
381 ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
382 ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
383 ComponentDto view = db.components().insertComponent(newView(db.getDefaultOrganization(), "V1").setDbKey("MyView"));
384 db.components().insertComponent(newProjectCopy(project, view));
385 RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
386 db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
387 allowAnyoneOnProjects(project, view);
388 indexIssuesAndViews();
391 .setParam(PARAM_COMPONENT_KEYS, view.getKey())
393 .assertJson(this.getClass(), "search_by_view_uuid.json");
397 public void search_by_sub_view_uuid() {
398 ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
399 ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
400 RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
401 db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
402 ComponentDto view = db.components().insertComponent(newView(db.getDefaultOrganization(), "V1").setDbKey("MyView"));
403 ComponentDto subView = db.components().insertComponent(newSubView(view, "SV1", "MySubView"));
404 db.components().insertComponent(newProjectCopy(project, subView));
405 allowAnyoneOnProjects(project, view, subView);
406 indexIssuesAndViews();
409 .setParam(PARAM_COMPONENT_KEYS, subView.getKey())
411 .assertJson(this.getClass(), "search_by_view_uuid.json");
415 public void search_by_sub_view_uuid_return_only_authorized_view() {
416 ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
417 ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
418 RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
419 db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
420 ComponentDto view = db.components().insertComponent(newView(db.getDefaultOrganization(), "V1").setDbKey("MyView"));
421 ComponentDto subView = db.components().insertComponent(newSubView(view, "SV1", "MySubView"));
422 db.components().insertComponent(newProjectCopy(project, subView));
423 // User has no permission on the view, no issue will be returned
424 allowAnyoneOnProjects(project);
425 indexIssuesAndViews();
428 .setParam(PARAM_COMPONENT_KEYS, subView.getKey())
430 .assertJson(this.getClass(), "no_issue.json");
434 public void search_by_application_key() {
435 ComponentDto application = db.components().insertPrivateApplication(db.getDefaultOrganization());
436 ComponentDto project1 = db.components().insertPrivateProject();
437 ComponentDto project2 = db.components().insertPrivateProject();
438 db.components().insertComponents(newProjectCopy(project1, application));
439 db.components().insertComponents(newProjectCopy(project2, application));
440 RuleDefinitionDto rule = db.rules().insertIssueRule();
441 IssueDto issue1 = db.issues().insertIssue(rule, project1, project1);
442 IssueDto issue2 = db.issues().insertIssue(rule, project2, project2);
443 allowAnyoneOnProjects(project1, project2, application);
444 userSession.addProjectPermission(USER, application);
445 indexIssuesAndViews();
447 SearchWsResponse result = ws.newRequest()
448 .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
449 .executeProtobuf(SearchWsResponse.class);
451 assertThat(result.getIssuesList()).extracting(Issue::getKey)
452 .containsExactlyInAnyOrder(issue1.getKey(), issue2.getKey());
456 public void search_by_application_key_and_branch() {
457 ComponentDto application = db.components().insertPrivateProject(c -> c.setQualifier(APP).setDbKey("app"));
458 ComponentDto applicationBranch1 = db.components().insertProjectBranch(application, a -> a.setKey("app-branch1"));
459 ComponentDto applicationBranch2 = db.components().insertProjectBranch(application, a -> a.setKey("app-branch2"));
460 ComponentDto project1 = db.components().insertPrivateProject(p -> p.setDbKey("prj1"));
461 ComponentDto project1Branch1 = db.components().insertProjectBranch(project1);
462 ComponentDto fileOnProject1Branch1 = db.components().insertComponent(newFileDto(project1Branch1));
463 ComponentDto project1Branch2 = db.components().insertProjectBranch(project1);
464 ComponentDto project2 = db.components().insertPrivateProject(p -> p.setDbKey("prj2"));
465 db.components().insertComponents(newProjectCopy(project1Branch1, applicationBranch1));
466 db.components().insertComponents(newProjectCopy(project2, applicationBranch1));
467 db.components().insertComponents(newProjectCopy(project1Branch2, applicationBranch2));
469 RuleDefinitionDto issueRule = db.rules().insertIssueRule();
470 RuleDefinitionDto hotspotRule = db.rules().insertHotspotRule();
471 IssueDto issueOnProject1 = db.issues().insertIssue(issueRule, project1, project1);
472 IssueDto issueOnProject1Branch1 = db.issues().insertIssue(issueRule, project1Branch1, project1Branch1);
473 db.issues().insertHotspot(hotspotRule, project1Branch1, project1Branch1);
474 IssueDto issueOnFileOnProject1Branch1 = db.issues().insertIssue(issueRule, project1Branch1, fileOnProject1Branch1);
475 IssueDto issueOnProject1Branch2 = db.issues().insertIssue(issueRule, project1Branch2, project1Branch2);
476 IssueDto issueOnProject2 = db.issues().insertIssue(issueRule, project2, project2);
477 db.issues().insertHotspot(hotspotRule, project2, project2);
478 allowAnyoneOnProjects(project1, project2, application);
479 userSession.addProjectPermission(USER, application);
480 indexIssuesAndViews();
482 // All issues on applicationBranch1
483 assertThat(ws.newRequest()
484 .setParam(PARAM_COMPONENT_KEYS, applicationBranch1.getKey())
485 .setParam(PARAM_BRANCH, applicationBranch1.getBranch())
486 .executeProtobuf(SearchWsResponse.class).getIssuesList())
487 .extracting(Issue::getKey, Issue::getComponent, Issue::getProject, Issue::getBranch, Issue::hasBranch)
488 .containsExactlyInAnyOrder(
489 tuple(issueOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch(), true),
490 tuple(issueOnFileOnProject1Branch1.getKey(), fileOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch(), true),
491 tuple(issueOnProject2.getKey(), project2.getKey(), project2.getKey(), "", false));
493 // Issues on project1Branch1
494 assertThat(ws.newRequest()
495 .setParam(PARAM_COMPONENT_KEYS, applicationBranch1.getKey())
496 .setParam(PARAM_PROJECTS, project1.getKey())
497 .setParam(PARAM_BRANCH, applicationBranch1.getBranch())
498 .executeProtobuf(SearchWsResponse.class).getIssuesList())
499 .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
500 .containsExactlyInAnyOrder(
501 tuple(issueOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch()),
502 tuple(issueOnFileOnProject1Branch1.getKey(), fileOnProject1Branch1.getKey(), project1Branch1.getBranch()));
506 public void ignore_application_without_browse_permission() {
507 ComponentDto project = db.components().insertPublicProject();
508 ComponentDto application = db.components().insertPublicApplication(db.getDefaultOrganization());
509 db.components().insertComponents(newProjectCopy("PC1", project, application));
510 RuleDefinitionDto rule = db.rules().insertIssueRule();
511 db.issues().insertIssue(rule, project, project);
512 allowAnyoneOnProjects(project);
513 indexIssuesAndViews();
515 SearchWsResponse result = ws.newRequest()
516 .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
517 .executeProtobuf(SearchWsResponse.class);
519 assertThat(result.getIssuesList()).isEmpty();
523 public void search_application_without_projects() {
524 ComponentDto project = db.components().insertPublicProject();
525 ComponentDto application = db.components().insertPublicApplication(db.getDefaultOrganization());
526 RuleDefinitionDto rule = db.rules().insertIssueRule();
527 db.issues().insertIssue(rule, project, project);
528 allowAnyoneOnProjects(project, application);
529 indexIssuesAndViews();
531 SearchWsResponse result = ws.newRequest()
532 .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
533 .executeProtobuf(SearchWsResponse.class);
535 assertThat(result.getIssuesList()).isEmpty();
539 public void search_by_application_and_by_leak() {
540 Date now = new Date();
541 RuleDefinitionDto rule = db.rules().insertIssueRule();
542 ComponentDto application = db.components().insertPublicApplication(db.getDefaultOrganization());
544 ComponentDto project1 = db.components().insertPublicProject();
545 db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime()));
546 db.components().insertComponents(newProjectCopy("PC1", project1, application));
547 IssueDto project1Issue1 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -10)));
548 IssueDto project1Issue2 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -20)));
550 ComponentDto project2 = db.components().insertPublicProject();
551 db.components().insertSnapshot(project2, s -> s.setPeriodDate(addDays(now, -25).getTime()));
552 db.components().insertComponents(newProjectCopy("PC2", project2, application));
553 IssueDto project2Issue1 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -15)));
554 IssueDto project2Issue2 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -30)));
555 // Permissions and index
556 allowAnyoneOnProjects(project1, project2, application);
557 indexIssuesAndViews();
559 SearchWsResponse result = ws.newRequest()
560 .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
561 .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
562 .executeProtobuf(SearchWsResponse.class);
564 assertThat(result.getIssuesList()).extracting(Issue::getKey)
565 .containsExactlyInAnyOrder(project1Issue1.getKey(), project2Issue1.getKey())
566 .doesNotContain(project1Issue2.getKey(), project2Issue2.getKey());
570 public void search_by_application_and_project() {
571 ComponentDto project1 = db.components().insertPublicProject();
572 ComponentDto project2 = db.components().insertPublicProject();
573 ComponentDto application = db.components().insertPublicApplication(db.getDefaultOrganization());
574 db.components().insertComponents(newProjectCopy("PC1", project1, application));
575 db.components().insertComponents(newProjectCopy("PC2", project2, application));
576 RuleDefinitionDto rule = db.rules().insertIssueRule();
577 IssueDto issue1 = db.issues().insertIssue(rule, project1, project1);
578 IssueDto issue2 = db.issues().insertIssue(rule, project2, project2);
579 allowAnyoneOnProjects(project1, project2, application);
580 indexIssuesAndViews();
582 SearchWsResponse result = ws.newRequest()
583 .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
584 .setParam(PARAM_PROJECT_KEYS, project1.getDbKey())
585 .executeProtobuf(SearchWsResponse.class);
587 assertThat(result.getIssuesList()).extracting(Issue::getKey)
588 .containsExactlyInAnyOrder(issue1.getKey())
589 .doesNotContain(issue2.getKey());
593 public void search_by_application_and_project_and_leak() {
594 Date now = new Date();
595 RuleDefinitionDto rule = db.rules().insertIssueRule();
596 ComponentDto application = db.components().insertPublicApplication(db.getDefaultOrganization());
598 ComponentDto project1 = db.components().insertPublicProject();
599 db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime()));
600 db.components().insertComponents(newProjectCopy("PC1", project1, application));
601 IssueDto project1Issue1 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -10)));
602 IssueDto project1Issue2 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -20)));
604 ComponentDto project2 = db.components().insertPublicProject();
605 db.components().insertSnapshot(project2, s -> s.setPeriodDate(addDays(now, -25).getTime()));
606 db.components().insertComponents(newProjectCopy("PC2", project2, application));
607 IssueDto project2Issue1 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -15)));
608 IssueDto project2Issue2 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -30)));
609 // Permissions and index
610 allowAnyoneOnProjects(project1, project2, application);
611 indexIssuesAndViews();
613 SearchWsResponse result = ws.newRequest()
614 .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
615 .setParam(PARAM_PROJECT_KEYS, project1.getDbKey())
616 .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
617 .executeProtobuf(SearchWsResponse.class);
619 assertThat(result.getIssuesList()).extracting(Issue::getKey)
620 .containsExactlyInAnyOrder(project1Issue1.getKey())
621 .doesNotContain(project1Issue2.getKey(), project2Issue1.getKey(), project2Issue2.getKey());
625 public void search_by_application_and_by_leak_when_one_project_has_no_leak() {
626 Date now = new Date();
627 RuleDefinitionDto rule = db.rules().insertIssueRule();
628 ComponentDto application = db.components().insertPublicApplication(db.getDefaultOrganization());
630 ComponentDto project1 = db.components().insertPublicProject();
631 db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime()));
632 db.components().insertComponents(newProjectCopy("PC1", project1, application));
633 IssueDto project1Issue1 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -10)));
634 IssueDto project1Issue2 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -20)));
635 // Project 2, without leak => no issue form it should be returned
636 ComponentDto project2 = db.components().insertPublicProject();
637 db.components().insertSnapshot(project2, s -> s.setPeriodDate(null));
638 db.components().insertComponents(newProjectCopy("PC2", project2, application));
639 IssueDto project2Issue1 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -15)));
640 IssueDto project2Issue2 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -30)));
641 // Permissions and index
642 allowAnyoneOnProjects(project1, project2, application);
643 indexIssuesAndViews();
645 SearchWsResponse result = ws.newRequest()
646 .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
647 .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
648 .executeProtobuf(SearchWsResponse.class);
650 assertThat(result.getIssuesList()).extracting(Issue::getKey)
651 .containsExactlyInAnyOrder(project1Issue1.getKey())
652 .doesNotContain(project1Issue2.getKey(), project2Issue1.getKey(), project2Issue2.getKey());
656 public void search_by_branch() {
657 RuleDefinitionDto rule = db.rules().insertIssueRule();
658 ComponentDto project = db.components().insertPublicProject();
659 ComponentDto file = db.components().insertComponent(newFileDto(project));
660 IssueDto issue = db.issues().insertIssue(rule, project, file);
662 ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH));
663 ComponentDto branchFile = db.components().insertComponent(newFileDto(branch));
664 IssueDto branchIssue = db.issues().insertIssue(rule, branch, branchFile);
665 allowAnyoneOnProjects(project);
666 indexIssuesAndViews();
668 // On component key + branch
669 assertThat(ws.newRequest()
670 .setParam(PARAM_COMPONENT_KEYS, project.getKey())
671 .setParam(PARAM_BRANCH, branch.getBranch())
672 .executeProtobuf(SearchWsResponse.class).getIssuesList())
673 .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
674 .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
676 // On project key + branch
677 assertThat(ws.newRequest()
678 .setParam(PARAM_PROJECT_KEYS, project.getKey())
679 .setParam(PARAM_BRANCH, branch.getBranch())
680 .executeProtobuf(SearchWsResponse.class).getIssuesList())
681 .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
682 .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
684 // On file key + branch
685 assertThat(ws.newRequest()
686 .setParam(PARAM_COMPONENT_KEYS, branchFile.getKey())
687 .setParam(PARAM_BRANCH, branch.getBranch())
688 .executeProtobuf(SearchWsResponse.class).getIssuesList())
689 .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
690 .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
694 public void return_branch_in_component_list() {
695 RuleDefinitionDto rule = db.rules().insertIssueRule();
696 ComponentDto project = db.components().insertPrivateProject();
697 ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
698 IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
699 ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH));
700 ComponentDto branchFile = db.components().insertComponent(newFileDto(branch));
701 IssueDto branchIssue = db.issues().insertIssue(rule, branch, branchFile);
702 allowAnyoneOnProjects(project);
703 indexIssuesAndViews();
705 SearchWsResponse result = ws.newRequest()
706 .setParam(PARAM_COMPONENT_KEYS, branch.getKey())
707 .setParam(PARAM_BRANCH, branch.getBranch())
708 .executeProtobuf(SearchWsResponse.class);
710 assertThat(result.getComponentsList())
711 .extracting(Issues.Component::getKey, Issues.Component::getBranch)
712 .containsExactlyInAnyOrder(
713 tuple(branchFile.getKey(), branchFile.getBranch()),
714 tuple(branch.getKey(), branch.getBranch()));
718 public void search_by_pull_request() {
719 RuleDefinitionDto rule = db.rules().insertIssueRule();
720 ComponentDto project = db.components().insertPrivateProject();
721 ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
722 IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
723 ComponentDto pullRequest = db.components().insertProjectBranch(project, b -> b.setBranchType(PULL_REQUEST));
724 ComponentDto pullRequestFile = db.components().insertComponent(newFileDto(pullRequest));
725 IssueDto pullRequestIssue = db.issues().insertIssue(rule, pullRequest, pullRequestFile);
726 allowAnyoneOnProjects(project);
727 indexIssuesAndViews();
729 SearchWsResponse result = ws.newRequest()
730 .setParam(PARAM_COMPONENT_KEYS, pullRequest.getKey())
731 .setParam(PARAM_PULL_REQUEST, pullRequest.getPullRequest())
732 .executeProtobuf(SearchWsResponse.class);
734 assertThat(result.getIssuesList())
735 .extracting(Issue::getKey, Issue::getComponent, Issue::getPullRequest)
736 .containsExactlyInAnyOrder(tuple(pullRequestIssue.getKey(), pullRequestFile.getKey(), pullRequestFile.getPullRequest()));
737 assertThat(result.getComponentsList())
738 .extracting(Issues.Component::getKey, Issues.Component::getPullRequest)
739 .containsExactlyInAnyOrder(
740 tuple(pullRequestFile.getKey(), pullRequestFile.getPullRequest()),
741 tuple(pullRequest.getKey(), pullRequest.getPullRequest()));
745 public void search_using_main_branch_name() {
746 RuleDefinitionDto rule = db.rules().insertIssueRule();
747 ComponentDto project = db.components().insertPublicProject();
748 ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
749 IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
750 allowAnyoneOnProjects(project);
751 indexIssuesAndViews();
753 SearchWsResponse result = ws.newRequest()
754 .setParam(PARAM_COMPONENT_KEYS, project.getKey())
755 .setParam(PARAM_BRANCH, "master")
756 .executeProtobuf(SearchWsResponse.class);
758 assertThat(result.getIssuesList())
759 .extracting(Issue::getKey, Issue::getComponent, Issue::hasBranch)
760 .containsExactlyInAnyOrder(tuple(projectIssue.getKey(), projectFile.getKey(), false));
761 assertThat(result.getComponentsList())
762 .extracting(Issues.Component::getKey, Issues.Component::hasBranch)
763 .containsExactlyInAnyOrder(
764 tuple(projectFile.getKey(), false),
765 tuple(project.getKey(), false));
769 public void does_not_return_branch_issues_on_not_contextualized_search() {
770 RuleDefinitionDto rule = db.rules().insertIssueRule();
771 ComponentDto project = db.components().insertPrivateProject();
772 ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
773 IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
774 ComponentDto branch = db.components().insertProjectBranch(project);
775 ComponentDto branchFile = db.components().insertComponent(newFileDto(branch));
776 IssueDto branchIssue = db.issues().insertIssue(rule, branch, branchFile);
777 allowAnyoneOnProjects(project);
778 indexIssuesAndViews();
780 SearchWsResponse result = ws.newRequest().executeProtobuf(SearchWsResponse.class);
782 assertThat(result.getIssuesList()).extracting(Issue::getKey)
783 .containsExactlyInAnyOrder(projectIssue.getKey())
784 .doesNotContain(branchIssue.getKey());
788 public void does_not_return_branch_issues_when_using_db_key() {
789 RuleDefinitionDto rule = db.rules().insertIssueRule();
790 ComponentDto project = db.components().insertPrivateProject();
791 ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
792 IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
793 ComponentDto branch = db.components().insertProjectBranch(project);
794 ComponentDto branchFile = db.components().insertComponent(newFileDto(branch));
795 IssueDto branchIssue = db.issues().insertIssue(rule, branch, branchFile);
796 allowAnyoneOnProjects(project);
799 SearchWsResponse result = ws.newRequest()
800 .setParam(PARAM_COMPONENT_KEYS, branch.getDbKey())
801 .executeProtobuf(SearchWsResponse.class);
803 assertThat(result.getIssuesList()).isEmpty();
806 private void allowAnyoneOnProjects(ComponentDto... projects) {
807 userSession.registerComponents(projects);
808 Arrays.stream(projects).forEach(p -> permissionIndexer.allowOnlyAnyone(p));
811 private void indexIssues() {
812 issueIndexer.indexAllIssues();
815 private void indexIssuesAndViews() {
817 viewIndexer.indexOnStartup(null);