]> source.dussan.org Git - sonarqube.git/blob
a5228b2add3fadf4a5edd3926a4e30f5c8579b73
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2022 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 package org.sonar.server.issue.ws;
21
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;
60
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;
82
83 public class SearchActionComponentsTest {
84
85   @Rule
86   public UserSessionRule userSession = UserSessionRule.standalone();
87   @Rule
88   public DbTester db = DbTester.create();
89   @Rule
90   public EsTester es = EsTester.create();
91
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);
104
105   private IssueIndexSyncProgressChecker issueIndexSyncProgressChecker = new IssueIndexSyncProgressChecker(db.getDbClient());
106
107   private WsActionTester ws = new WsActionTester(
108     new SearchAction(userSession, issueIndex, issueQueryFactory, issueIndexSyncProgressChecker, searchResponseLoader, searchResponseFormat,
109       System2.INSTANCE, dbClient));
110
111   @Test
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);
118     indexIssues();
119
120     SearchWsResponse result = ws.newRequest().executeProtobuf(SearchWsResponse.class);
121
122     assertThat(result.getIssuesList()).extracting(Issues.Issue::getKey)
123       .containsExactlyInAnyOrder(issue.getKey());
124   }
125
126   @Test
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);
136     indexIssues();
137
138     SearchWsResponse response = ws.newRequest().executeProtobuf(SearchWsResponse.class);
139
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));
148   }
149
150   @Test
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);
161     indexIssues();
162
163     assertThat(ws.newRequest()
164       .setParam(PARAM_COMPONENT_KEYS, module1.getKey())
165       .executeProtobuf(SearchWsResponse.class).getIssuesList()).extracting(Issue::getKey)
166         .containsExactlyInAnyOrder(issue1.getKey());
167   }
168
169   @Test
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);
182     indexIssues();
183
184     ws.newRequest()
185       .setParam(PARAM_COMPONENT_KEYS, project.getKey())
186       .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
187       .execute()
188       .assertJson(this.getClass(), "search_since_leak_period.json");
189   }
190
191   @Test
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);
205     indexIssues();
206
207     ws.newRequest()
208       .setParam(PARAM_COMPONENT_KEYS, project.getKey())
209       .setParam(PARAM_FILES, file.path())
210       .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
211       .execute()
212       .assertJson(this.getClass(), "search_since_leak_period.json");
213   }
214
215   @Test
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);
222     indexIssues();
223
224     ws.newRequest()
225       .setParam(PARAM_FILES, file.path())
226       .execute()
227       .assertJson(this.getClass(), "search_by_file_uuid.json");
228
229     ws.newRequest()
230       .setParam(PARAM_FILES, "unknown")
231       .execute()
232       .assertJson(this.getClass(), "no_issue.json");
233   }
234
235   @Test
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);
244     indexIssues();
245
246     ws.newRequest()
247       .setParam(PARAM_COMPONENT_KEYS, file.getKey())
248       .execute()
249       .assertJson(this.getClass(), "search_by_file_key.json");
250
251     ws.newRequest()
252       .setParam(PARAM_COMPONENT_KEYS, unitTest.getKey())
253       .execute()
254       .assertJson(this.getClass(), "search_by_test_key.json");
255   }
256
257   @Test
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);
265     indexIssues();
266
267     ws.newRequest()
268       .setParam(PARAM_COMPONENT_KEYS, directory.getKey())
269       .execute()
270       .assertJson(this.getClass(), "search_by_file_uuid.json");
271
272     ws.newRequest()
273       .setParam(PARAM_DIRECTORIES, "unknown")
274       .execute()
275       .assertJson(this.getClass(), "no_issue.json");
276
277     ws.newRequest()
278       .setParam(PARAM_DIRECTORIES, "src/main/java/dir")
279       .execute()
280       .assertJson(this.getClass(), "search_by_file_uuid.json");
281
282     ws.newRequest()
283       .setParam(PARAM_DIRECTORIES, "src/main/java")
284       .execute()
285       .assertJson(this.getClass(), "no_issue.json");
286   }
287
288   @Test
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();
298
299     ws.newRequest()
300       .setParam(PARAM_COMPONENT_KEYS, view.getKey())
301       .execute()
302       .assertJson(this.getClass(), "search_by_view_uuid.json");
303   }
304
305   @Test
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();
316
317     ws.newRequest()
318       .setParam(PARAM_COMPONENT_KEYS, subView.getKey())
319       .execute()
320       .assertJson(this.getClass(), "search_by_view_uuid.json");
321   }
322
323   @Test
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();
335
336     ws.newRequest()
337       .setParam(PARAM_COMPONENT_KEYS, subView.getKey())
338       .execute()
339       .assertJson(this.getClass(), "no_issue.json");
340   }
341
342   @Test
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();
355
356     SearchWsResponse result = ws.newRequest()
357       .setParam(PARAM_COMPONENT_KEYS, application.getKey())
358       .executeProtobuf(SearchWsResponse.class);
359
360     assertThat(result.getIssuesList()).extracting(Issue::getKey)
361       .containsExactlyInAnyOrder(issue1.getKey(), issue2.getKey());
362   }
363
364   @Test
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));
377
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();
390
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));
401
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()));
412   }
413
414   @Test
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();
423
424     SearchWsResponse result = ws.newRequest()
425       .setParam(PARAM_COMPONENT_KEYS, application.getKey())
426       .executeProtobuf(SearchWsResponse.class);
427
428     assertThat(result.getIssuesList()).isEmpty();
429   }
430
431   @Test
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();
439
440     SearchWsResponse result = ws.newRequest()
441       .setParam(PARAM_COMPONENT_KEYS, application.getKey())
442       .executeProtobuf(SearchWsResponse.class);
443
444     assertThat(result.getIssuesList()).isEmpty();
445   }
446
447   @Test
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();
452     // Project 1
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)));
458     // Project 2
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();
467
468     SearchWsResponse result = ws.newRequest()
469       .setParam(PARAM_COMPONENT_KEYS, application.getKey())
470       .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
471       .executeProtobuf(SearchWsResponse.class);
472
473     assertThat(result.getIssuesList()).extracting(Issue::getKey)
474       .containsExactlyInAnyOrder(project1Issue1.getKey(), project2Issue1.getKey())
475       .doesNotContain(project1Issue2.getKey(), project2Issue2.getKey());
476   }
477
478   @Test
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();
490
491     SearchWsResponse result = ws.newRequest()
492       .setParam(PARAM_COMPONENT_KEYS, application.getKey())
493       .setParam(PARAM_PROJECTS, project1.getKey())
494       .executeProtobuf(SearchWsResponse.class);
495
496     assertThat(result.getIssuesList()).extracting(Issue::getKey)
497       .containsExactlyInAnyOrder(issue1.getKey())
498       .doesNotContain(issue2.getKey());
499   }
500
501   @Test
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();
506     // Project 1
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)));
512     // Project 2
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();
521
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);
527
528     assertThat(result.getIssuesList()).extracting(Issue::getKey)
529       .containsExactlyInAnyOrder(project1Issue1.getKey())
530       .doesNotContain(project1Issue2.getKey(), project2Issue1.getKey(), project2Issue2.getKey());
531   }
532
533   @Test
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();
538     // Project 1
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();
553
554     SearchWsResponse result = ws.newRequest()
555       .setParam(PARAM_COMPONENT_KEYS, application.getKey())
556       .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
557       .executeProtobuf(SearchWsResponse.class);
558
559     assertThat(result.getIssuesList()).extracting(Issue::getKey)
560       .containsExactlyInAnyOrder(project1Issue1.getKey())
561       .doesNotContain(project1Issue2.getKey(), project2Issue1.getKey(), project2Issue2.getKey());
562   }
563
564   @Test
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);
570
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();
576
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()));
584
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()));
599   }
600
601   @Test
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();
612
613     SearchWsResponse result = ws.newRequest()
614       .setParam(PARAM_COMPONENT_KEYS, branch.getKey())
615       .setParam(PARAM_BRANCH, branch.getBranch())
616       .executeProtobuf(SearchWsResponse.class);
617
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()));
623   }
624
625   @Test
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);
631
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();
638
639     SearchWsResponse result = ws.newRequest()
640       .setParam(PARAM_COMPONENT_KEYS, pullRequest.getKey())
641       .setParam(PARAM_PULL_REQUEST, pullRequestKey)
642       .executeProtobuf(SearchWsResponse.class);
643
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));
652   }
653
654   @Test
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();
662
663     SearchWsResponse result = ws.newRequest()
664       .setParam(PARAM_COMPONENT_KEYS, project.getKey())
665       .setParam(PARAM_BRANCH, "master")
666       .executeProtobuf(SearchWsResponse.class);
667
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));
676   }
677
678   @Test
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();
689
690     SearchWsResponse result = ws.newRequest().executeProtobuf(SearchWsResponse.class);
691
692     assertThat(result.getIssuesList()).extracting(Issue::getKey)
693       .containsExactlyInAnyOrder(projectIssue.getKey())
694       .doesNotContain(branchIssue.getKey());
695   }
696
697   private void allowAnyoneOnProjects(ComponentDto... projects) {
698     userSession.registerComponents(projects);
699     Arrays.stream(projects).forEach(p -> permissionIndexer.allowOnlyAnyone(p));
700   }
701
702   private void allowAnyoneOnApplication(ComponentDto application, ComponentDto... projects) {
703     userSession.registerApplication(application);
704     Arrays.stream(projects).forEach(p -> permissionIndexer.allowOnlyAnyone(p));
705   }
706
707   private void indexIssues() {
708     issueIndexer.indexAllIssues();
709   }
710
711   private void indexIssuesAndViews() {
712     indexIssues();
713     viewIndexer.indexAll();
714   }
715 }