3 * Copyright (C) 2009-2022 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.apache.commons.lang.RandomStringUtils;
26 import org.junit.Rule;
27 import org.junit.Test;
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.component.ComponentTesting;
37 import org.sonar.db.issue.IssueDto;
38 import org.sonar.db.rule.RuleDto;
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.IssueIndexSyncProgressChecker;
46 import org.sonar.server.issue.index.IssueIndexer;
47 import org.sonar.server.issue.index.IssueIteratorFactory;
48 import org.sonar.server.issue.index.IssueQueryFactory;
49 import org.sonar.server.issue.workflow.FunctionExecutor;
50 import org.sonar.server.issue.workflow.IssueWorkflow;
51 import org.sonar.server.permission.index.PermissionIndexerTester;
52 import org.sonar.server.permission.index.WebAuthorizationTypeSupport;
53 import org.sonar.server.tester.UserSessionRule;
54 import org.sonar.server.view.index.ViewIndexer;
55 import org.sonar.server.ws.WsActionTester;
56 import org.sonarqube.ws.Issues;
57 import org.sonarqube.ws.Issues.Component;
58 import org.sonarqube.ws.Issues.Issue;
59 import org.sonarqube.ws.Issues.SearchWsResponse;
61 import static org.assertj.core.api.Assertions.assertThat;
62 import static org.assertj.core.api.Assertions.tuple;
63 import static org.sonar.api.resources.Qualifiers.APP;
64 import static org.sonar.api.utils.DateUtils.addDays;
65 import static org.sonar.api.utils.DateUtils.parseDateTime;
66 import static org.sonar.api.web.UserRole.USER;
67 import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
68 import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02;
69 import static org.sonar.db.component.BranchType.BRANCH;
70 import static org.sonar.db.component.BranchType.PULL_REQUEST;
71 import static org.sonar.db.component.ComponentTesting.newDirectory;
72 import static org.sonar.db.component.ComponentTesting.newFileDto;
73 import static org.sonar.db.component.ComponentTesting.newModuleDto;
74 import static org.sonar.db.component.ComponentTesting.newProjectCopy;
75 import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BRANCH;
76 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS;
77 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_DIRECTORIES;
78 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_FILES;
79 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECTS;
80 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PULL_REQUEST;
81 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SINCE_LEAK_PERIOD;
83 public class SearchActionComponentsTest {
86 public UserSessionRule userSession = UserSessionRule.standalone();
88 public DbTester db = DbTester.create();
90 public EsTester es = EsTester.create();
92 private DbClient dbClient = db.getDbClient();
93 private IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession, new WebAuthorizationTypeSupport(userSession));
94 private IssueIndexer issueIndexer = new IssueIndexer(es.client(), dbClient, new IssueIteratorFactory(dbClient), null);
95 private ViewIndexer viewIndexer = new ViewIndexer(dbClient, es.client());
96 private IssueQueryFactory issueQueryFactory = new IssueQueryFactory(dbClient, Clock.systemUTC(), userSession);
97 private IssueFieldsSetter issueFieldsSetter = new IssueFieldsSetter();
98 private IssueWorkflow issueWorkflow = new IssueWorkflow(new FunctionExecutor(issueFieldsSetter), issueFieldsSetter);
99 private SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSession, dbClient, new TransitionService(userSession, issueWorkflow));
100 private Languages languages = new Languages();
101 private UserResponseFormatter userFormatter = new UserResponseFormatter(new AvatarResolverImpl());
102 private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new TextRangeResponseFormatter(), userFormatter);
103 private PermissionIndexerTester permissionIndexer = new PermissionIndexerTester(es, issueIndexer);
105 private IssueIndexSyncProgressChecker issueIndexSyncProgressChecker = new IssueIndexSyncProgressChecker(db.getDbClient());
107 private WsActionTester ws = new WsActionTester(
108 new SearchAction(userSession, issueIndex, issueQueryFactory, issueIndexSyncProgressChecker, searchResponseLoader, searchResponseFormat,
109 System2.INSTANCE, dbClient));
112 public void search_all_issues_when_no_parameter() {
113 RuleDto rule = db.rules().insertIssueRule();
114 ComponentDto project = db.components().insertPublicProject();
115 ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
116 IssueDto issue = db.issues().insertIssue(rule, project, projectFile);
117 allowAnyoneOnProjects(project);
120 SearchWsResponse result = ws.newRequest().executeProtobuf(SearchWsResponse.class);
122 assertThat(result.getIssuesList()).extracting(Issues.Issue::getKey)
123 .containsExactlyInAnyOrder(issue.getKey());
127 public void issues_on_different_projects() {
128 RuleDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
129 ComponentDto project = db.components().insertPublicProject();
130 ComponentDto file = db.components().insertComponent(newFileDto(project));
131 IssueDto issue1 = db.issues().insertIssue(rule, project, file);
132 ComponentDto project2 = db.components().insertPublicProject();
133 ComponentDto file2 = db.components().insertComponent(newFileDto(project2));
134 IssueDto issue2 = db.issues().insertIssue(rule, project2, file2);
135 allowAnyoneOnProjects(project, project2);
138 SearchWsResponse response = ws.newRequest().executeProtobuf(SearchWsResponse.class);
140 assertThat(response.getIssuesList())
141 .extracting(Issue::getKey, Issue::getComponent, Issue::getProject)
142 .containsExactlyInAnyOrder(
143 tuple(issue1.getKey(), file.getKey(), project.getKey()),
144 tuple(issue2.getKey(), file2.getKey(), project2.getKey()));
145 assertThat(response.getComponentsList())
146 .extracting(Component::getKey, Component::getEnabled)
147 .containsExactlyInAnyOrder(tuple(project.getKey(), true), tuple(file.getKey(), true), tuple(project2.getKey(), true), tuple(file2.getKey(), true));
151 public void search_by_module() {
152 ComponentDto project = db.components().insertPublicProject();
153 ComponentDto module1 = db.components().insertComponent(newModuleDto(project));
154 ComponentDto file1 = db.components().insertComponent(newFileDto(module1));
155 ComponentDto module2 = db.components().insertComponent(newModuleDto(project));
156 ComponentDto file2 = db.components().insertComponent(newFileDto(module2));
157 RuleDto rule = db.rules().insertIssueRule();
158 IssueDto issue1 = db.issues().insertIssue(rule, project, file1);
159 IssueDto issue2 = db.issues().insertIssue(rule, project, file2);
160 allowAnyoneOnProjects(project);
163 assertThat(ws.newRequest()
164 .setParam(PARAM_COMPONENT_KEYS, module1.getKey())
165 .executeProtobuf(SearchWsResponse.class).getIssuesList()).extracting(Issue::getKey)
166 .containsExactlyInAnyOrder(issue1.getKey());
170 public void search_since_leak_period_on_project() {
171 ComponentDto project = db.components().insertPublicProject(p -> p.setKey("PK1"));
172 ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setKey("FK1"));
173 db.components().insertSnapshot(project, a -> a.setPeriodDate(parseDateTime("2015-09-03T00:00:00+0100").getTime()));
174 RuleDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
175 IssueDto issueAfterLeak = db.issues().insertIssue(rule, project, file, i -> i.setKee(UUID_EXAMPLE_01)
176 .setIssueCreationDate(parseDateTime("2015-09-04T00:00:00+0100"))
177 .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100")));
178 IssueDto issueBeforeLeak = db.issues().insertIssue(rule, project, file, i -> i.setKee(UUID_EXAMPLE_02)
179 .setIssueCreationDate(parseDateTime("2014-09-04T00:00:00+0100"))
180 .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100")));
181 allowAnyoneOnProjects(project);
185 .setParam(PARAM_COMPONENT_KEYS, project.getKey())
186 .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
188 .assertJson(this.getClass(), "search_since_leak_period.json");
192 public void search_since_leak_period_on_file_in_module_project() {
193 ComponentDto project = db.components().insertPublicProject(p -> p.setKey("PK1"));
194 ComponentDto module = db.components().insertComponent(newModuleDto(project));
195 ComponentDto file = db.components().insertComponent(newFileDto(module, null, "F1").setKey("FK1"));
196 db.components().insertSnapshot(project, a -> a.setPeriodDate(parseDateTime("2015-09-03T00:00:00+0100").getTime()));
197 RuleDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
198 IssueDto issueAfterLeak = db.issues().insertIssue(rule, project, file, i -> i.setKee(UUID_EXAMPLE_01)
199 .setIssueCreationDate(parseDateTime("2015-09-04T00:00:00+0100"))
200 .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100")));
201 IssueDto issueBeforeLeak = db.issues().insertIssue(rule, project, file, i -> i.setKee(UUID_EXAMPLE_02)
202 .setIssueCreationDate(parseDateTime("2014-09-04T00:00:00+0100"))
203 .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100")));
204 allowAnyoneOnProjects(project);
208 .setParam(PARAM_COMPONENT_KEYS, project.getKey())
209 .setParam(PARAM_FILES, file.path())
210 .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
212 .assertJson(this.getClass(), "search_since_leak_period.json");
216 public void search_by_file_uuid() {
217 ComponentDto project = db.components().insertPublicProject(p -> p.setKey("PK1"));
218 ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setKey("FK1"));
219 RuleDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
220 IssueDto issue = db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
221 allowAnyoneOnProjects(project);
225 .setParam(PARAM_FILES, file.path())
227 .assertJson(this.getClass(), "search_by_file_uuid.json");
230 .setParam(PARAM_FILES, "unknown")
232 .assertJson(this.getClass(), "no_issue.json");
236 public void search_by_file_key() {
237 ComponentDto project = db.components().insertPublicProject(p -> p.setKey("PK1"));
238 ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setKey("FK1"));
239 ComponentDto unitTest = db.components().insertComponent(newFileDto(project, null, "F2").setQualifier(Qualifiers.UNIT_TEST_FILE).setKey("FK2"));
240 RuleDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
241 IssueDto issueOnFile = db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
242 IssueDto issueOnTest = db.issues().insertIssue(rule, project, unitTest, i -> i.setKee("2bd4eac2-b650-4037-80bc-7b1182fd47d4"));
243 allowAnyoneOnProjects(project);
247 .setParam(PARAM_COMPONENT_KEYS, file.getKey())
249 .assertJson(this.getClass(), "search_by_file_key.json");
252 .setParam(PARAM_COMPONENT_KEYS, unitTest.getKey())
254 .assertJson(this.getClass(), "search_by_test_key.json");
258 public void search_by_directory_path() {
259 ComponentDto project = db.components().insertPublicProject(p -> p.setKey("PK1"));
260 ComponentDto directory = db.components().insertComponent(newDirectory(project, "D1", "src/main/java/dir"));
261 ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setKey("FK1").setPath(directory.path() + "/MyComponent.java"));
262 RuleDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
263 db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
264 allowAnyoneOnProjects(project);
268 .setParam(PARAM_COMPONENT_KEYS, directory.getKey())
270 .assertJson(this.getClass(), "search_by_file_uuid.json");
273 .setParam(PARAM_DIRECTORIES, "unknown")
275 .assertJson(this.getClass(), "no_issue.json");
278 .setParam(PARAM_DIRECTORIES, "src/main/java/dir")
280 .assertJson(this.getClass(), "search_by_file_uuid.json");
283 .setParam(PARAM_DIRECTORIES, "src/main/java")
285 .assertJson(this.getClass(), "no_issue.json");
289 public void search_by_view_uuid() {
290 ComponentDto project = db.components().insertPublicProject(p -> p.setKey("PK1"));
291 ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setKey("FK1"));
292 ComponentDto view = db.components().insertComponent(ComponentTesting.newPortfolio("V1").setKey("MyView"));
293 db.components().insertComponent(newProjectCopy(project, view));
294 RuleDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
295 db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
296 allowAnyoneOnProjects(project, view);
297 indexIssuesAndViews();
300 .setParam(PARAM_COMPONENT_KEYS, view.getKey())
302 .assertJson(this.getClass(), "search_by_view_uuid.json");
306 public void search_by_sub_view_uuid() {
307 ComponentDto project = db.components().insertPublicProject(p -> p.setKey("PK1"));
308 ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setKey("FK1"));
309 RuleDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
310 db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
311 ComponentDto view = db.components().insertComponent(ComponentTesting.newPortfolio("V1").setKey("MyView"));
312 ComponentDto subView = db.components().insertComponent(ComponentTesting.newSubPortfolio(view, "SV1", "MySubView"));
313 db.components().insertComponent(newProjectCopy(project, subView));
314 allowAnyoneOnProjects(project, view, subView);
315 indexIssuesAndViews();
318 .setParam(PARAM_COMPONENT_KEYS, subView.getKey())
320 .assertJson(this.getClass(), "search_by_view_uuid.json");
324 public void search_by_sub_view_uuid_return_only_authorized_view() {
325 ComponentDto project = db.components().insertPublicProject(p -> p.setKey("PK1"));
326 ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setKey("FK1"));
327 RuleDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
328 db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
329 ComponentDto view = db.components().insertComponent(ComponentTesting.newPortfolio("V1").setKey("MyView"));
330 ComponentDto subView = db.components().insertComponent(ComponentTesting.newSubPortfolio(view, "SV1", "MySubView"));
331 db.components().insertComponent(newProjectCopy(project, subView));
332 // User has no permission on the view, no issue will be returned
333 allowAnyoneOnProjects(project);
334 indexIssuesAndViews();
337 .setParam(PARAM_COMPONENT_KEYS, subView.getKey())
339 .assertJson(this.getClass(), "no_issue.json");
343 public void search_by_application_key() {
344 ComponentDto application = db.components().insertPrivateApplication();
345 ComponentDto project1 = db.components().insertPrivateProject();
346 ComponentDto project2 = db.components().insertPrivateProject();
347 db.components().insertComponents(newProjectCopy(project1, application));
348 db.components().insertComponents(newProjectCopy(project2, application));
349 RuleDto rule = db.rules().insertIssueRule();
350 IssueDto issue1 = db.issues().insertIssue(rule, project1, project1);
351 IssueDto issue2 = db.issues().insertIssue(rule, project2, project2);
352 allowAnyoneOnApplication(application, project1, project2);
353 userSession.addProjectPermission(USER, application);
354 indexIssuesAndViews();
356 SearchWsResponse result = ws.newRequest()
357 .setParam(PARAM_COMPONENT_KEYS, application.getKey())
358 .executeProtobuf(SearchWsResponse.class);
360 assertThat(result.getIssuesList()).extracting(Issue::getKey)
361 .containsExactlyInAnyOrder(issue1.getKey(), issue2.getKey());
365 public void search_by_application_key_and_branch() {
366 ComponentDto application = db.components().insertPrivateProject(c -> c.setQualifier(APP).setKey("app"));
367 ComponentDto applicationBranch1 = db.components().insertProjectBranch(application, a -> a.setKey("app-branch1"));
368 ComponentDto applicationBranch2 = db.components().insertProjectBranch(application, a -> a.setKey("app-branch2"));
369 ComponentDto project1 = db.components().insertPrivateProject(p -> p.setKey("prj1"));
370 ComponentDto project1Branch1 = db.components().insertProjectBranch(project1);
371 ComponentDto fileOnProject1Branch1 = db.components().insertComponent(newFileDto(project1Branch1));
372 ComponentDto project1Branch2 = db.components().insertProjectBranch(project1);
373 ComponentDto project2 = db.components().insertPrivateProject(p -> p.setKey("prj2"));
374 db.components().insertComponents(newProjectCopy(project1Branch1, applicationBranch1));
375 db.components().insertComponents(newProjectCopy(project2, applicationBranch1));
376 db.components().insertComponents(newProjectCopy(project1Branch2, applicationBranch2));
378 RuleDto issueRule = db.rules().insertIssueRule();
379 RuleDto hotspotRule = db.rules().insertHotspotRule();
380 IssueDto issueOnProject1 = db.issues().insertIssue(issueRule, project1, project1);
381 IssueDto issueOnProject1Branch1 = db.issues().insertIssue(issueRule, project1Branch1, project1Branch1);
382 db.issues().insertHotspot(hotspotRule, project1Branch1, project1Branch1);
383 IssueDto issueOnFileOnProject1Branch1 = db.issues().insertIssue(issueRule, project1Branch1, fileOnProject1Branch1);
384 IssueDto issueOnProject1Branch2 = db.issues().insertIssue(issueRule, project1Branch2, project1Branch2);
385 IssueDto issueOnProject2 = db.issues().insertIssue(issueRule, project2, project2);
386 db.issues().insertHotspot(hotspotRule, project2, project2);
387 allowAnyoneOnProjects(project1, project2, application);
388 userSession.addProjectPermission(USER, application);
389 indexIssuesAndViews();
391 // All issues on applicationBranch1
392 assertThat(ws.newRequest()
393 .setParam(PARAM_COMPONENT_KEYS, applicationBranch1.getKey())
394 .setParam(PARAM_BRANCH, applicationBranch1.getBranch())
395 .executeProtobuf(SearchWsResponse.class).getIssuesList())
396 .extracting(Issue::getKey, Issue::getComponent, Issue::getProject, Issue::getBranch, Issue::hasBranch)
397 .containsExactlyInAnyOrder(
398 tuple(issueOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch(), true),
399 tuple(issueOnFileOnProject1Branch1.getKey(), fileOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch(), true),
400 tuple(issueOnProject2.getKey(), project2.getKey(), project2.getKey(), "", false));
402 // Issues on project1Branch1
403 assertThat(ws.newRequest()
404 .setParam(PARAM_COMPONENT_KEYS, applicationBranch1.getKey())
405 .setParam(PARAM_PROJECTS, project1.getKey())
406 .setParam(PARAM_BRANCH, applicationBranch1.getBranch())
407 .executeProtobuf(SearchWsResponse.class).getIssuesList())
408 .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
409 .containsExactlyInAnyOrder(
410 tuple(issueOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch()),
411 tuple(issueOnFileOnProject1Branch1.getKey(), fileOnProject1Branch1.getKey(), project1Branch1.getBranch()));
415 public void ignore_application_without_browse_permission() {
416 ComponentDto project = db.components().insertPublicProject();
417 ComponentDto application = db.components().insertPublicApplication();
418 db.components().insertComponents(newProjectCopy("PC1", project, application));
419 RuleDto rule = db.rules().insertIssueRule();
420 db.issues().insertIssue(rule, project, project);
421 allowAnyoneOnProjects(project);
422 indexIssuesAndViews();
424 SearchWsResponse result = ws.newRequest()
425 .setParam(PARAM_COMPONENT_KEYS, application.getKey())
426 .executeProtobuf(SearchWsResponse.class);
428 assertThat(result.getIssuesList()).isEmpty();
432 public void search_application_without_projects() {
433 ComponentDto project = db.components().insertPublicProject();
434 ComponentDto application = db.components().insertPublicApplication();
435 RuleDto rule = db.rules().insertIssueRule();
436 db.issues().insertIssue(rule, project, project);
437 allowAnyoneOnProjects(project, application);
438 indexIssuesAndViews();
440 SearchWsResponse result = ws.newRequest()
441 .setParam(PARAM_COMPONENT_KEYS, application.getKey())
442 .executeProtobuf(SearchWsResponse.class);
444 assertThat(result.getIssuesList()).isEmpty();
448 public void search_by_application_and_by_leak() {
449 Date now = new Date();
450 RuleDto rule = db.rules().insertIssueRule();
451 ComponentDto application = db.components().insertPublicApplication();
453 ComponentDto project1 = db.components().insertPublicProject();
454 db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime()));
455 db.components().insertComponents(newProjectCopy("PC1", project1, application));
456 IssueDto project1Issue1 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -10)));
457 IssueDto project1Issue2 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -20)));
459 ComponentDto project2 = db.components().insertPublicProject();
460 db.components().insertSnapshot(project2, s -> s.setPeriodDate(addDays(now, -25).getTime()));
461 db.components().insertComponents(newProjectCopy("PC2", project2, application));
462 IssueDto project2Issue1 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -15)));
463 IssueDto project2Issue2 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -30)));
464 // Permissions and index
465 allowAnyoneOnApplication(application, project1, project2);
466 indexIssuesAndViews();
468 SearchWsResponse result = ws.newRequest()
469 .setParam(PARAM_COMPONENT_KEYS, application.getKey())
470 .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
471 .executeProtobuf(SearchWsResponse.class);
473 assertThat(result.getIssuesList()).extracting(Issue::getKey)
474 .containsExactlyInAnyOrder(project1Issue1.getKey(), project2Issue1.getKey())
475 .doesNotContain(project1Issue2.getKey(), project2Issue2.getKey());
479 public void search_by_application_and_project() {
480 ComponentDto project1 = db.components().insertPublicProject();
481 ComponentDto project2 = db.components().insertPublicProject();
482 ComponentDto application = db.components().insertPublicApplication();
483 db.components().insertComponents(newProjectCopy("PC1", project1, application));
484 db.components().insertComponents(newProjectCopy("PC2", project2, application));
485 RuleDto rule = db.rules().insertIssueRule();
486 IssueDto issue1 = db.issues().insertIssue(rule, project1, project1);
487 IssueDto issue2 = db.issues().insertIssue(rule, project2, project2);
488 allowAnyoneOnApplication(application, project1, project2);
489 indexIssuesAndViews();
491 SearchWsResponse result = ws.newRequest()
492 .setParam(PARAM_COMPONENT_KEYS, application.getKey())
493 .setParam(PARAM_PROJECTS, project1.getKey())
494 .executeProtobuf(SearchWsResponse.class);
496 assertThat(result.getIssuesList()).extracting(Issue::getKey)
497 .containsExactlyInAnyOrder(issue1.getKey())
498 .doesNotContain(issue2.getKey());
502 public void search_by_application_and_project_and_leak() {
503 Date now = new Date();
504 RuleDto rule = db.rules().insertIssueRule();
505 ComponentDto application = db.components().insertPublicApplication();
507 ComponentDto project1 = db.components().insertPublicProject();
508 db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime()));
509 db.components().insertComponents(newProjectCopy("PC1", project1, application));
510 IssueDto project1Issue1 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -10)));
511 IssueDto project1Issue2 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -20)));
513 ComponentDto project2 = db.components().insertPublicProject();
514 db.components().insertSnapshot(project2, s -> s.setPeriodDate(addDays(now, -25).getTime()));
515 db.components().insertComponents(newProjectCopy("PC2", project2, application));
516 IssueDto project2Issue1 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -15)));
517 IssueDto project2Issue2 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -30)));
518 // Permissions and index
519 allowAnyoneOnApplication(application, project1, project2);
520 indexIssuesAndViews();
522 SearchWsResponse result = ws.newRequest()
523 .setParam(PARAM_COMPONENT_KEYS, application.getKey())
524 .setParam(PARAM_PROJECTS, project1.getKey())
525 .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
526 .executeProtobuf(SearchWsResponse.class);
528 assertThat(result.getIssuesList()).extracting(Issue::getKey)
529 .containsExactlyInAnyOrder(project1Issue1.getKey())
530 .doesNotContain(project1Issue2.getKey(), project2Issue1.getKey(), project2Issue2.getKey());
534 public void search_by_application_and_by_leak_when_one_project_has_no_leak() {
535 Date now = new Date();
536 RuleDto rule = db.rules().insertIssueRule();
537 ComponentDto application = db.components().insertPublicApplication();
539 ComponentDto project1 = db.components().insertPublicProject();
540 db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime()));
541 db.components().insertComponents(newProjectCopy("PC1", project1, application));
542 IssueDto project1Issue1 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -10)));
543 IssueDto project1Issue2 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -20)));
544 // Project 2, without leak => no issue form it should be returned
545 ComponentDto project2 = db.components().insertPublicProject();
546 db.components().insertSnapshot(project2, s -> s.setPeriodDate(null));
547 db.components().insertComponents(newProjectCopy("PC2", project2, application));
548 IssueDto project2Issue1 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -15)));
549 IssueDto project2Issue2 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -30)));
550 // Permissions and index
551 allowAnyoneOnApplication(application, project1, project2);
552 indexIssuesAndViews();
554 SearchWsResponse result = ws.newRequest()
555 .setParam(PARAM_COMPONENT_KEYS, application.getKey())
556 .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
557 .executeProtobuf(SearchWsResponse.class);
559 assertThat(result.getIssuesList()).extracting(Issue::getKey)
560 .containsExactlyInAnyOrder(project1Issue1.getKey())
561 .doesNotContain(project1Issue2.getKey(), project2Issue1.getKey(), project2Issue2.getKey());
565 public void search_by_branch() {
566 RuleDto rule = db.rules().insertIssueRule();
567 ComponentDto project = db.components().insertPublicProject();
568 ComponentDto file = db.components().insertComponent(newFileDto(project));
569 IssueDto issue = db.issues().insertIssue(rule, project, file);
571 ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH));
572 ComponentDto branchFile = db.components().insertComponent(newFileDto(branch));
573 IssueDto branchIssue = db.issues().insertIssue(rule, branch, branchFile);
574 allowAnyoneOnProjects(project);
575 indexIssuesAndViews();
577 // On component key + branch
578 assertThat(ws.newRequest()
579 .setParam(PARAM_COMPONENT_KEYS, project.getKey())
580 .setParam(PARAM_BRANCH, branch.getBranch())
581 .executeProtobuf(SearchWsResponse.class).getIssuesList())
582 .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
583 .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
585 // On project key + branch
586 assertThat(ws.newRequest()
587 .setParam(PARAM_PROJECTS, project.getKey())
588 .setParam(PARAM_BRANCH, branch.getBranch())
589 .executeProtobuf(SearchWsResponse.class).getIssuesList())
590 .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
591 .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
592 // On file key + branch
593 assertThat(ws.newRequest()
594 .setParam(PARAM_COMPONENT_KEYS, branchFile.getKey())
595 .setParam(PARAM_BRANCH, branch.getBranch())
596 .executeProtobuf(SearchWsResponse.class).getIssuesList())
597 .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
598 .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
602 public void return_branch_in_component_list() {
603 RuleDto rule = db.rules().insertIssueRule();
604 ComponentDto project = db.components().insertPrivateProject();
605 ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
606 IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
607 ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH));
608 ComponentDto branchFile = db.components().insertComponent(newFileDto(branch));
609 IssueDto branchIssue = db.issues().insertIssue(rule, branch, branchFile);
610 allowAnyoneOnProjects(project);
611 indexIssuesAndViews();
613 SearchWsResponse result = ws.newRequest()
614 .setParam(PARAM_COMPONENT_KEYS, branch.getKey())
615 .setParam(PARAM_BRANCH, branch.getBranch())
616 .executeProtobuf(SearchWsResponse.class);
618 assertThat(result.getComponentsList())
619 .extracting(Issues.Component::getKey, Issues.Component::getBranch)
620 .containsExactlyInAnyOrder(
621 tuple(branchFile.getKey(), branchFile.getBranch()),
622 tuple(branch.getKey(), branch.getBranch()));
626 public void search_by_pull_request() {
627 RuleDto rule = db.rules().insertIssueRule();
628 ComponentDto project = db.components().insertPrivateProject();
629 ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
630 IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
632 String pullRequestKey = RandomStringUtils.randomAlphanumeric(100);
633 ComponentDto pullRequest = db.components().insertProjectBranch(project, b -> b.setBranchType(PULL_REQUEST).setKey(pullRequestKey));
634 ComponentDto pullRequestFile = db.components().insertComponent(newFileDto(pullRequest));
635 IssueDto pullRequestIssue = db.issues().insertIssue(rule, pullRequest, pullRequestFile);
636 allowAnyoneOnProjects(project);
637 indexIssuesAndViews();
639 SearchWsResponse result = ws.newRequest()
640 .setParam(PARAM_COMPONENT_KEYS, pullRequest.getKey())
641 .setParam(PARAM_PULL_REQUEST, pullRequestKey)
642 .executeProtobuf(SearchWsResponse.class);
644 assertThat(result.getIssuesList())
645 .extracting(Issue::getKey, Issue::getComponent, Issue::getPullRequest)
646 .containsExactlyInAnyOrder(tuple(pullRequestIssue.getKey(), pullRequestFile.getKey(), pullRequestKey));
647 assertThat(result.getComponentsList())
648 .extracting(Issues.Component::getKey, Issues.Component::getPullRequest)
649 .containsExactlyInAnyOrder(
650 tuple(pullRequestFile.getKey(), pullRequestKey),
651 tuple(pullRequest.getKey(), pullRequestKey));
655 public void search_using_main_branch_name() {
656 RuleDto rule = db.rules().insertIssueRule();
657 ComponentDto project = db.components().insertPublicProject();
658 ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
659 IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
660 allowAnyoneOnProjects(project);
661 indexIssuesAndViews();
663 SearchWsResponse result = ws.newRequest()
664 .setParam(PARAM_COMPONENT_KEYS, project.getKey())
665 .setParam(PARAM_BRANCH, "master")
666 .executeProtobuf(SearchWsResponse.class);
668 assertThat(result.getIssuesList())
669 .extracting(Issue::getKey, Issue::getComponent, Issue::hasBranch)
670 .containsExactlyInAnyOrder(tuple(projectIssue.getKey(), projectFile.getKey(), false));
671 assertThat(result.getComponentsList())
672 .extracting(Issues.Component::getKey, Issues.Component::hasBranch)
673 .containsExactlyInAnyOrder(
674 tuple(projectFile.getKey(), false),
675 tuple(project.getKey(), false));
679 public void does_not_return_branch_issues_on_not_contextualized_search() {
680 RuleDto rule = db.rules().insertIssueRule();
681 ComponentDto project = db.components().insertPrivateProject();
682 ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
683 IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
684 ComponentDto branch = db.components().insertProjectBranch(project);
685 ComponentDto branchFile = db.components().insertComponent(newFileDto(branch));
686 IssueDto branchIssue = db.issues().insertIssue(rule, branch, branchFile);
687 allowAnyoneOnProjects(project);
688 indexIssuesAndViews();
690 SearchWsResponse result = ws.newRequest().executeProtobuf(SearchWsResponse.class);
692 assertThat(result.getIssuesList()).extracting(Issue::getKey)
693 .containsExactlyInAnyOrder(projectIssue.getKey())
694 .doesNotContain(branchIssue.getKey());
698 public void does_not_return_branch_issues_when_using_db_key() {
699 RuleDto rule = db.rules().insertIssueRule();
700 ComponentDto project = db.components().insertPrivateProject();
701 ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
702 IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
703 ComponentDto branch = db.components().insertProjectBranch(project);
704 ComponentDto branchFile = db.components().insertComponent(newFileDto(branch));
705 IssueDto branchIssue = db.issues().insertIssue(rule, branch, branchFile);
706 allowAnyoneOnProjects(project);
709 SearchWsResponse result = ws.newRequest()
710 .setParam(PARAM_COMPONENT_KEYS, branch.getKey())
711 .executeProtobuf(SearchWsResponse.class);
713 assertThat(result.getIssuesList()).isEmpty();
716 private void allowAnyoneOnProjects(ComponentDto... projects) {
717 userSession.registerComponents(projects);
718 Arrays.stream(projects).forEach(p -> permissionIndexer.allowOnlyAnyone(p));
721 private void allowAnyoneOnApplication(ComponentDto application, ComponentDto... projects) {
722 userSession.registerApplication(application);
723 Arrays.stream(projects).forEach(p -> permissionIndexer.allowOnlyAnyone(p));
726 private void indexIssues() {
727 issueIndexer.indexAllIssues();
730 private void indexIssuesAndViews() {
732 viewIndexer.indexAll();