]> source.dussan.org Git - sonarqube.git/blob
ad121f485fd003ec25c2f27f42cb2fa911d8e382
[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.junit.Rule;
26 import org.junit.Test;
27 import org.sonar.api.resources.Languages;
28 import org.sonar.api.resources.Qualifiers;
29 import org.sonar.api.rule.RuleKey;
30 import org.sonar.api.utils.Durations;
31 import org.sonar.api.utils.System2;
32 import org.sonar.db.DbClient;
33 import org.sonar.db.DbTester;
34 import org.sonar.db.component.ComponentDto;
35 import org.sonar.db.component.ComponentTesting;
36 import org.sonar.db.issue.IssueDto;
37 import org.sonar.db.rule.RuleDefinitionDto;
38 import org.sonar.server.es.EsTester;
39 import org.sonar.server.issue.AvatarResolverImpl;
40 import org.sonar.server.issue.IssueFieldsSetter;
41 import org.sonar.server.issue.TextRangeResponseFormatter;
42 import org.sonar.server.issue.TransitionService;
43 import org.sonar.server.issue.index.IssueIndex;
44 import org.sonar.server.issue.index.IssueIndexSyncProgressChecker;
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;
59
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.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BRANCH;
75 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS;
76 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_DIRECTORIES;
77 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_FILES;
78 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECTS;
79 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PULL_REQUEST;
80 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SINCE_LEAK_PERIOD;
81
82 public class SearchActionComponentsTest {
83
84   @Rule
85   public UserSessionRule userSession = UserSessionRule.standalone();
86   @Rule
87   public DbTester db = DbTester.create();
88   @Rule
89   public EsTester es = EsTester.create();
90
91   private DbClient dbClient = db.getDbClient();
92   private IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession, new WebAuthorizationTypeSupport(userSession));
93   private IssueIndexer issueIndexer = new IssueIndexer(es.client(), dbClient, new IssueIteratorFactory(dbClient), null);
94   private ViewIndexer viewIndexer = new ViewIndexer(dbClient, es.client());
95   private IssueQueryFactory issueQueryFactory = new IssueQueryFactory(dbClient, Clock.systemUTC(), userSession);
96   private IssueFieldsSetter issueFieldsSetter = new IssueFieldsSetter();
97   private IssueWorkflow issueWorkflow = new IssueWorkflow(new FunctionExecutor(issueFieldsSetter), issueFieldsSetter);
98   private SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSession, dbClient, new TransitionService(userSession, issueWorkflow));
99   private Languages languages = new Languages();
100   private UserResponseFormatter userFormatter = new UserResponseFormatter(new AvatarResolverImpl());
101   private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new TextRangeResponseFormatter(), userFormatter);
102   private PermissionIndexerTester permissionIndexer = new PermissionIndexerTester(es, issueIndexer);
103
104   private IssueIndexSyncProgressChecker issueIndexSyncProgressChecker = new IssueIndexSyncProgressChecker(db.getDbClient());
105
106   private WsActionTester ws = new WsActionTester(
107     new SearchAction(userSession, issueIndex, issueQueryFactory, issueIndexSyncProgressChecker, searchResponseLoader, searchResponseFormat,
108       System2.INSTANCE, dbClient));
109
110   @Test
111   public void search_all_issues_when_no_parameter() {
112     RuleDefinitionDto rule = db.rules().insertIssueRule();
113     ComponentDto project = db.components().insertPublicProject();
114     ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
115     IssueDto issue = db.issues().insertIssue(rule, project, projectFile);
116     allowAnyoneOnProjects(project);
117     indexIssues();
118
119     SearchWsResponse result = ws.newRequest().executeProtobuf(SearchWsResponse.class);
120
121     assertThat(result.getIssuesList()).extracting(Issues.Issue::getKey)
122       .containsExactlyInAnyOrder(issue.getKey());
123   }
124
125   @Test
126   public void issues_on_different_projects() {
127     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
128     ComponentDto project = db.components().insertPublicProject();
129     ComponentDto file = db.components().insertComponent(newFileDto(project));
130     IssueDto issue1 = db.issues().insertIssue(rule, project, file);
131     ComponentDto project2 = db.components().insertPublicProject();
132     ComponentDto file2 = db.components().insertComponent(newFileDto(project2));
133     IssueDto issue2 = db.issues().insertIssue(rule, project2, file2);
134     allowAnyoneOnProjects(project, project2);
135     indexIssues();
136
137     SearchWsResponse response = ws.newRequest().executeProtobuf(SearchWsResponse.class);
138
139     assertThat(response.getIssuesList())
140       .extracting(Issue::getKey, Issue::getComponent, Issue::getProject)
141       .containsExactlyInAnyOrder(
142         tuple(issue1.getKey(), file.getKey(), project.getKey()),
143         tuple(issue2.getKey(), file2.getKey(), project2.getKey()));
144     assertThat(response.getComponentsList())
145       .extracting(Component::getKey, Component::getEnabled)
146       .containsExactlyInAnyOrder(tuple(project.getKey(), true), tuple(file.getKey(), true), tuple(project2.getKey(), true), tuple(file2.getKey(), true));
147   }
148
149   @Test
150   public void search_by_module() {
151     ComponentDto project = db.components().insertPublicProject();
152     ComponentDto module1 = db.components().insertComponent(newModuleDto(project));
153     ComponentDto file1 = db.components().insertComponent(newFileDto(module1));
154     ComponentDto module2 = db.components().insertComponent(newModuleDto(project));
155     ComponentDto file2 = db.components().insertComponent(newFileDto(module2));
156     RuleDefinitionDto rule = db.rules().insertIssueRule();
157     IssueDto issue1 = db.issues().insertIssue(rule, project, file1);
158     IssueDto issue2 = db.issues().insertIssue(rule, project, file2);
159     allowAnyoneOnProjects(project);
160     indexIssues();
161
162     assertThat(ws.newRequest()
163       .setParam(PARAM_COMPONENT_KEYS, module1.getKey())
164       .executeProtobuf(SearchWsResponse.class).getIssuesList()).extracting(Issue::getKey)
165         .containsExactlyInAnyOrder(issue1.getKey());
166   }
167
168   @Test
169   public void do_not_return_module_key_on_single_module_projects() {
170     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
171     ComponentDto module = db.components().insertComponent(newModuleDto("M1", project).setDbKey("MK1"));
172     ComponentDto file = db.components().insertComponent(newFileDto(module, null, "F1").setDbKey("FK1"));
173     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
174     db.issues().insertIssue(rule, project, file, i -> i.setKee("ISSUE_IN_MODULE"));
175     db.issues().insertIssue(rule, project, project, i -> i.setKee("ISSUE_IN_ROOT_MODULE"));
176     allowAnyoneOnProjects(project);
177     indexIssues();
178
179     SearchWsResponse searchResponse = ws.newRequest().executeProtobuf(SearchWsResponse.class);
180     assertThat(searchResponse.getIssuesCount()).isEqualTo(2);
181
182     for (Issue issue : searchResponse.getIssuesList()) {
183       assertThat(issue.getProject()).isEqualTo("PK1");
184       if (issue.getKey().equals("ISSUE_IN_MODULE")) {
185         assertThat(issue.getSubProject()).isEqualTo("MK1");
186       } else if (issue.getKey().equals("ISSUE_IN_ROOT_MODULE")) {
187         assertThat(issue.hasSubProject()).isFalse();
188       }
189     }
190   }
191
192   @Test
193   public void search_since_leak_period_on_project() {
194     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
195     ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
196     db.components().insertSnapshot(project, a -> a.setPeriodDate(parseDateTime("2015-09-03T00:00:00+0100").getTime()));
197     RuleDefinitionDto 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.getDbKey())
209       .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
210       .execute()
211       .assertJson(this.getClass(), "search_since_leak_period.json");
212   }
213
214   @Test
215   public void search_since_leak_period_on_file_in_module_project() {
216     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
217     ComponentDto module = db.components().insertComponent(newModuleDto(project));
218     ComponentDto file = db.components().insertComponent(newFileDto(module, null, "F1").setDbKey("FK1"));
219     db.components().insertSnapshot(project, a -> a.setPeriodDate(parseDateTime("2015-09-03T00:00:00+0100").getTime()));
220     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
221     IssueDto issueAfterLeak = db.issues().insertIssue(rule, project, file, i -> i.setKee(UUID_EXAMPLE_01)
222       .setIssueCreationDate(parseDateTime("2015-09-04T00:00:00+0100"))
223       .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100")));
224     IssueDto issueBeforeLeak = db.issues().insertIssue(rule, project, file, i -> i.setKee(UUID_EXAMPLE_02)
225       .setIssueCreationDate(parseDateTime("2014-09-04T00:00:00+0100"))
226       .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100")));
227     allowAnyoneOnProjects(project);
228     indexIssues();
229
230     ws.newRequest()
231       .setParam(PARAM_COMPONENT_KEYS, project.getDbKey())
232       .setParam(PARAM_FILES, file.path())
233       .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
234       .execute()
235       .assertJson(this.getClass(), "search_since_leak_period.json");
236   }
237
238   @Test
239   public void search_by_file_uuid() {
240     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
241     ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
242     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
243     IssueDto issue = db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
244     allowAnyoneOnProjects(project);
245     indexIssues();
246
247     ws.newRequest()
248       .setParam(PARAM_FILES, file.path())
249       .execute()
250       .assertJson(this.getClass(), "search_by_file_uuid.json");
251
252     ws.newRequest()
253       .setParam(PARAM_FILES, "unknown")
254       .execute()
255       .assertJson(this.getClass(), "no_issue.json");
256   }
257
258   @Test
259   public void search_by_file_key() {
260     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
261     ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
262     ComponentDto unitTest = db.components().insertComponent(newFileDto(project, null, "F2").setQualifier(Qualifiers.UNIT_TEST_FILE).setDbKey("FK2"));
263     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
264     IssueDto issueOnFile = db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
265     IssueDto issueOnTest = db.issues().insertIssue(rule, project, unitTest, i -> i.setKee("2bd4eac2-b650-4037-80bc-7b1182fd47d4"));
266     allowAnyoneOnProjects(project);
267     indexIssues();
268
269     ws.newRequest()
270       .setParam(PARAM_COMPONENT_KEYS, file.getKey())
271       .execute()
272       .assertJson(this.getClass(), "search_by_file_key.json");
273
274     ws.newRequest()
275       .setParam(PARAM_COMPONENT_KEYS, unitTest.getKey())
276       .execute()
277       .assertJson(this.getClass(), "search_by_test_key.json");
278   }
279
280   @Test
281   public void search_by_directory_path() {
282     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
283     ComponentDto directory = db.components().insertComponent(newDirectory(project, "D1", "src/main/java/dir"));
284     ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1").setPath(directory.path() + "/MyComponent.java"));
285     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
286     db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
287     allowAnyoneOnProjects(project);
288     indexIssues();
289
290     ws.newRequest()
291       .setParam(PARAM_COMPONENT_KEYS, directory.getKey())
292       .execute()
293       .assertJson(this.getClass(), "search_by_file_uuid.json");
294
295     ws.newRequest()
296       .setParam(PARAM_DIRECTORIES, "unknown")
297       .execute()
298       .assertJson(this.getClass(), "no_issue.json");
299
300     ws.newRequest()
301       .setParam(PARAM_DIRECTORIES, "src/main/java/dir")
302       .execute()
303       .assertJson(this.getClass(), "search_by_file_uuid.json");
304
305     ws.newRequest()
306       .setParam(PARAM_DIRECTORIES, "src/main/java")
307       .execute()
308       .assertJson(this.getClass(), "no_issue.json");
309   }
310
311   @Test
312   public void search_by_directory_path_in_different_modules() {
313     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
314     ComponentDto module1 = db.components().insertComponent(newModuleDto("M1", project).setDbKey("MK1"));
315     ComponentDto module2 = db.components().insertComponent(newModuleDto("M2", project).setDbKey("MK2"));
316     ComponentDto directory1 = db.components().insertComponent(newDirectory(module1, "D1", "src/main/java/dir"));
317     ComponentDto directory2 = db.components().insertComponent(newDirectory(module2, "D2", "src/main/java/dir"));
318     ComponentDto file1 = db.components().insertComponent(newFileDto(module1, directory1, "F1").setDbKey("FK1").setPath(directory1.path() + "/MyComponent.java"));
319     db.components().insertComponent(newFileDto(module2, directory2, "F2").setDbKey("FK2").setPath(directory2.path() + "/MyComponent.java"));
320     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
321     db.issues().insertIssue(rule, project, file1, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
322     allowAnyoneOnProjects(project);
323     indexIssues();
324
325     ws.newRequest()
326       .setParam(PARAM_COMPONENT_KEYS, directory1.getKey())
327       .execute()
328       .assertJson(this.getClass(), "search_by_directory_uuid.json");
329
330     ws.newRequest()
331       .setParam(PARAM_COMPONENT_KEYS, directory2.getKey())
332       .execute()
333       .assertJson(this.getClass(), "no_issue.json");
334
335     ws.newRequest()
336       .setParam(PARAM_DIRECTORIES, "src/main/java/dir")
337       .execute()
338       .assertJson(this.getClass(), "search_by_directory_uuid.json");
339
340     ws.newRequest()
341       .setParam(PARAM_DIRECTORIES, "src/main/java")
342       .execute()
343       .assertJson(this.getClass(), "no_issue.json");
344   }
345
346   @Test
347   public void search_by_view_uuid() {
348     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
349     ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
350     ComponentDto view = db.components().insertComponent(ComponentTesting.newPortfolio("V1").setDbKey("MyView"));
351     db.components().insertComponent(newProjectCopy(project, view));
352     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
353     db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
354     allowAnyoneOnProjects(project, view);
355     indexIssuesAndViews();
356
357     ws.newRequest()
358       .setParam(PARAM_COMPONENT_KEYS, view.getKey())
359       .execute()
360       .assertJson(this.getClass(), "search_by_view_uuid.json");
361   }
362
363   @Test
364   public void search_by_sub_view_uuid() {
365     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
366     ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
367     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
368     db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
369     ComponentDto view = db.components().insertComponent(ComponentTesting.newPortfolio("V1").setDbKey("MyView"));
370     ComponentDto subView = db.components().insertComponent(ComponentTesting.newSubPortfolio(view, "SV1", "MySubView"));
371     db.components().insertComponent(newProjectCopy(project, subView));
372     allowAnyoneOnProjects(project, view, subView);
373     indexIssuesAndViews();
374
375     ws.newRequest()
376       .setParam(PARAM_COMPONENT_KEYS, subView.getKey())
377       .execute()
378       .assertJson(this.getClass(), "search_by_view_uuid.json");
379   }
380
381   @Test
382   public void search_by_sub_view_uuid_return_only_authorized_view() {
383     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
384     ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
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     ComponentDto view = db.components().insertComponent(ComponentTesting.newPortfolio("V1").setDbKey("MyView"));
388     ComponentDto subView = db.components().insertComponent(ComponentTesting.newSubPortfolio(view, "SV1", "MySubView"));
389     db.components().insertComponent(newProjectCopy(project, subView));
390     // User has no permission on the view, no issue will be returned
391     allowAnyoneOnProjects(project);
392     indexIssuesAndViews();
393
394     ws.newRequest()
395       .setParam(PARAM_COMPONENT_KEYS, subView.getKey())
396       .execute()
397       .assertJson(this.getClass(), "no_issue.json");
398   }
399
400   @Test
401   public void search_by_application_key() {
402     ComponentDto application = db.components().insertPrivateApplication();
403     ComponentDto project1 = db.components().insertPrivateProject();
404     ComponentDto project2 = db.components().insertPrivateProject();
405     db.components().insertComponents(newProjectCopy(project1, application));
406     db.components().insertComponents(newProjectCopy(project2, application));
407     RuleDefinitionDto rule = db.rules().insertIssueRule();
408     IssueDto issue1 = db.issues().insertIssue(rule, project1, project1);
409     IssueDto issue2 = db.issues().insertIssue(rule, project2, project2);
410     allowAnyoneOnApplication(application, project1, project2);
411     userSession.addProjectPermission(USER, application);
412     indexIssuesAndViews();
413
414     SearchWsResponse result = ws.newRequest()
415       .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
416       .executeProtobuf(SearchWsResponse.class);
417
418     assertThat(result.getIssuesList()).extracting(Issue::getKey)
419       .containsExactlyInAnyOrder(issue1.getKey(), issue2.getKey());
420   }
421
422   @Test
423   public void search_by_application_key_and_branch() {
424     ComponentDto application = db.components().insertPrivateProject(c -> c.setQualifier(APP).setDbKey("app"));
425     ComponentDto applicationBranch1 = db.components().insertProjectBranch(application, a -> a.setKey("app-branch1"));
426     ComponentDto applicationBranch2 = db.components().insertProjectBranch(application, a -> a.setKey("app-branch2"));
427     ComponentDto project1 = db.components().insertPrivateProject(p -> p.setDbKey("prj1"));
428     ComponentDto project1Branch1 = db.components().insertProjectBranch(project1);
429     ComponentDto fileOnProject1Branch1 = db.components().insertComponent(newFileDto(project1Branch1));
430     ComponentDto project1Branch2 = db.components().insertProjectBranch(project1);
431     ComponentDto project2 = db.components().insertPrivateProject(p -> p.setDbKey("prj2"));
432     db.components().insertComponents(newProjectCopy(project1Branch1, applicationBranch1));
433     db.components().insertComponents(newProjectCopy(project2, applicationBranch1));
434     db.components().insertComponents(newProjectCopy(project1Branch2, applicationBranch2));
435
436     RuleDefinitionDto issueRule = db.rules().insertIssueRule();
437     RuleDefinitionDto hotspotRule = db.rules().insertHotspotRule();
438     IssueDto issueOnProject1 = db.issues().insertIssue(issueRule, project1, project1);
439     IssueDto issueOnProject1Branch1 = db.issues().insertIssue(issueRule, project1Branch1, project1Branch1);
440     db.issues().insertHotspot(hotspotRule, project1Branch1, project1Branch1);
441     IssueDto issueOnFileOnProject1Branch1 = db.issues().insertIssue(issueRule, project1Branch1, fileOnProject1Branch1);
442     IssueDto issueOnProject1Branch2 = db.issues().insertIssue(issueRule, project1Branch2, project1Branch2);
443     IssueDto issueOnProject2 = db.issues().insertIssue(issueRule, project2, project2);
444     db.issues().insertHotspot(hotspotRule, project2, project2);
445     allowAnyoneOnProjects(project1, project2, application);
446     userSession.addProjectPermission(USER, application);
447     indexIssuesAndViews();
448
449     // All issues on applicationBranch1
450     assertThat(ws.newRequest()
451       .setParam(PARAM_COMPONENT_KEYS, applicationBranch1.getKey())
452       .setParam(PARAM_BRANCH, applicationBranch1.getBranch())
453       .executeProtobuf(SearchWsResponse.class).getIssuesList())
454         .extracting(Issue::getKey, Issue::getComponent, Issue::getProject, Issue::getBranch, Issue::hasBranch)
455         .containsExactlyInAnyOrder(
456           tuple(issueOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch(), true),
457           tuple(issueOnFileOnProject1Branch1.getKey(), fileOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch(), true),
458           tuple(issueOnProject2.getKey(), project2.getKey(), project2.getKey(), "", false));
459
460     // Issues on project1Branch1
461     assertThat(ws.newRequest()
462       .setParam(PARAM_COMPONENT_KEYS, applicationBranch1.getKey())
463       .setParam(PARAM_PROJECTS, project1.getKey())
464       .setParam(PARAM_BRANCH, applicationBranch1.getBranch())
465       .executeProtobuf(SearchWsResponse.class).getIssuesList())
466         .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
467         .containsExactlyInAnyOrder(
468           tuple(issueOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch()),
469           tuple(issueOnFileOnProject1Branch1.getKey(), fileOnProject1Branch1.getKey(), project1Branch1.getBranch()));
470   }
471
472   @Test
473   public void ignore_application_without_browse_permission() {
474     ComponentDto project = db.components().insertPublicProject();
475     ComponentDto application = db.components().insertPublicApplication();
476     db.components().insertComponents(newProjectCopy("PC1", project, application));
477     RuleDefinitionDto rule = db.rules().insertIssueRule();
478     db.issues().insertIssue(rule, project, project);
479     allowAnyoneOnProjects(project);
480     indexIssuesAndViews();
481
482     SearchWsResponse result = ws.newRequest()
483       .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
484       .executeProtobuf(SearchWsResponse.class);
485
486     assertThat(result.getIssuesList()).isEmpty();
487   }
488
489   @Test
490   public void search_application_without_projects() {
491     ComponentDto project = db.components().insertPublicProject();
492     ComponentDto application = db.components().insertPublicApplication();
493     RuleDefinitionDto rule = db.rules().insertIssueRule();
494     db.issues().insertIssue(rule, project, project);
495     allowAnyoneOnProjects(project, application);
496     indexIssuesAndViews();
497
498     SearchWsResponse result = ws.newRequest()
499       .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
500       .executeProtobuf(SearchWsResponse.class);
501
502     assertThat(result.getIssuesList()).isEmpty();
503   }
504
505   @Test
506   public void search_by_application_and_by_leak() {
507     Date now = new Date();
508     RuleDefinitionDto rule = db.rules().insertIssueRule();
509     ComponentDto application = db.components().insertPublicApplication();
510     // Project 1
511     ComponentDto project1 = db.components().insertPublicProject();
512     db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime()));
513     db.components().insertComponents(newProjectCopy("PC1", project1, application));
514     IssueDto project1Issue1 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -10)));
515     IssueDto project1Issue2 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -20)));
516     // Project 2
517     ComponentDto project2 = db.components().insertPublicProject();
518     db.components().insertSnapshot(project2, s -> s.setPeriodDate(addDays(now, -25).getTime()));
519     db.components().insertComponents(newProjectCopy("PC2", project2, application));
520     IssueDto project2Issue1 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -15)));
521     IssueDto project2Issue2 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -30)));
522     // Permissions and index
523     allowAnyoneOnApplication(application, project1, project2);
524     indexIssuesAndViews();
525
526     SearchWsResponse result = ws.newRequest()
527       .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
528       .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
529       .executeProtobuf(SearchWsResponse.class);
530
531     assertThat(result.getIssuesList()).extracting(Issue::getKey)
532       .containsExactlyInAnyOrder(project1Issue1.getKey(), project2Issue1.getKey())
533       .doesNotContain(project1Issue2.getKey(), project2Issue2.getKey());
534   }
535
536   @Test
537   public void search_by_application_and_project() {
538     ComponentDto project1 = db.components().insertPublicProject();
539     ComponentDto project2 = db.components().insertPublicProject();
540     ComponentDto application = db.components().insertPublicApplication();
541     db.components().insertComponents(newProjectCopy("PC1", project1, application));
542     db.components().insertComponents(newProjectCopy("PC2", project2, application));
543     RuleDefinitionDto rule = db.rules().insertIssueRule();
544     IssueDto issue1 = db.issues().insertIssue(rule, project1, project1);
545     IssueDto issue2 = db.issues().insertIssue(rule, project2, project2);
546     allowAnyoneOnApplication(application, project1, project2);
547     indexIssuesAndViews();
548
549     SearchWsResponse result = ws.newRequest()
550       .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
551       .setParam(PARAM_PROJECTS, project1.getDbKey())
552       .executeProtobuf(SearchWsResponse.class);
553
554     assertThat(result.getIssuesList()).extracting(Issue::getKey)
555       .containsExactlyInAnyOrder(issue1.getKey())
556       .doesNotContain(issue2.getKey());
557   }
558
559   @Test
560   public void search_by_application_and_project_and_leak() {
561     Date now = new Date();
562     RuleDefinitionDto rule = db.rules().insertIssueRule();
563     ComponentDto application = db.components().insertPublicApplication();
564     // Project 1
565     ComponentDto project1 = db.components().insertPublicProject();
566     db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime()));
567     db.components().insertComponents(newProjectCopy("PC1", project1, application));
568     IssueDto project1Issue1 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -10)));
569     IssueDto project1Issue2 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -20)));
570     // Project 2
571     ComponentDto project2 = db.components().insertPublicProject();
572     db.components().insertSnapshot(project2, s -> s.setPeriodDate(addDays(now, -25).getTime()));
573     db.components().insertComponents(newProjectCopy("PC2", project2, application));
574     IssueDto project2Issue1 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -15)));
575     IssueDto project2Issue2 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -30)));
576     // Permissions and index
577     allowAnyoneOnApplication(application, project1, project2);
578     indexIssuesAndViews();
579
580     SearchWsResponse result = ws.newRequest()
581       .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
582       .setParam(PARAM_PROJECTS, project1.getDbKey())
583       .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
584       .executeProtobuf(SearchWsResponse.class);
585
586     assertThat(result.getIssuesList()).extracting(Issue::getKey)
587       .containsExactlyInAnyOrder(project1Issue1.getKey())
588       .doesNotContain(project1Issue2.getKey(), project2Issue1.getKey(), project2Issue2.getKey());
589   }
590
591   @Test
592   public void search_by_application_and_by_leak_when_one_project_has_no_leak() {
593     Date now = new Date();
594     RuleDefinitionDto rule = db.rules().insertIssueRule();
595     ComponentDto application = db.components().insertPublicApplication();
596     // Project 1
597     ComponentDto project1 = db.components().insertPublicProject();
598     db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime()));
599     db.components().insertComponents(newProjectCopy("PC1", project1, application));
600     IssueDto project1Issue1 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -10)));
601     IssueDto project1Issue2 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -20)));
602     // Project 2, without leak => no issue form it should be returned
603     ComponentDto project2 = db.components().insertPublicProject();
604     db.components().insertSnapshot(project2, s -> s.setPeriodDate(null));
605     db.components().insertComponents(newProjectCopy("PC2", project2, application));
606     IssueDto project2Issue1 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -15)));
607     IssueDto project2Issue2 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -30)));
608     // Permissions and index
609     allowAnyoneOnApplication(application, project1, project2);
610     indexIssuesAndViews();
611
612     SearchWsResponse result = ws.newRequest()
613       .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
614       .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
615       .executeProtobuf(SearchWsResponse.class);
616
617     assertThat(result.getIssuesList()).extracting(Issue::getKey)
618       .containsExactlyInAnyOrder(project1Issue1.getKey())
619       .doesNotContain(project1Issue2.getKey(), project2Issue1.getKey(), project2Issue2.getKey());
620   }
621
622   @Test
623   public void search_by_branch() {
624     RuleDefinitionDto rule = db.rules().insertIssueRule();
625     ComponentDto project = db.components().insertPublicProject();
626     ComponentDto file = db.components().insertComponent(newFileDto(project));
627     IssueDto issue = db.issues().insertIssue(rule, project, file);
628
629     ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH));
630     ComponentDto branchFile = db.components().insertComponent(newFileDto(branch));
631     IssueDto branchIssue = db.issues().insertIssue(rule, branch, branchFile);
632     allowAnyoneOnProjects(project);
633     indexIssuesAndViews();
634
635     // On component key + branch
636     assertThat(ws.newRequest()
637       .setParam(PARAM_COMPONENT_KEYS, project.getKey())
638       .setParam(PARAM_BRANCH, branch.getBranch())
639       .executeProtobuf(SearchWsResponse.class).getIssuesList())
640         .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
641         .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
642
643     // On project key + branch
644     assertThat(ws.newRequest()
645       .setParam(PARAM_PROJECTS, project.getKey())
646       .setParam(PARAM_BRANCH, branch.getBranch())
647       .executeProtobuf(SearchWsResponse.class).getIssuesList())
648         .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
649         .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
650     // On file key + branch
651     assertThat(ws.newRequest()
652       .setParam(PARAM_COMPONENT_KEYS, branchFile.getKey())
653       .setParam(PARAM_BRANCH, branch.getBranch())
654       .executeProtobuf(SearchWsResponse.class).getIssuesList())
655         .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
656         .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
657   }
658
659   @Test
660   public void return_branch_in_component_list() {
661     RuleDefinitionDto rule = db.rules().insertIssueRule();
662     ComponentDto project = db.components().insertPrivateProject();
663     ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
664     IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
665     ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH));
666     ComponentDto branchFile = db.components().insertComponent(newFileDto(branch));
667     IssueDto branchIssue = db.issues().insertIssue(rule, branch, branchFile);
668     allowAnyoneOnProjects(project);
669     indexIssuesAndViews();
670
671     SearchWsResponse result = ws.newRequest()
672       .setParam(PARAM_COMPONENT_KEYS, branch.getKey())
673       .setParam(PARAM_BRANCH, branch.getBranch())
674       .executeProtobuf(SearchWsResponse.class);
675
676     assertThat(result.getComponentsList())
677       .extracting(Issues.Component::getKey, Issues.Component::getBranch)
678       .containsExactlyInAnyOrder(
679         tuple(branchFile.getKey(), branchFile.getBranch()),
680         tuple(branch.getKey(), branch.getBranch()));
681   }
682
683   @Test
684   public void search_by_pull_request() {
685     RuleDefinitionDto rule = db.rules().insertIssueRule();
686     ComponentDto project = db.components().insertPrivateProject();
687     ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
688     IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
689     ComponentDto pullRequest = db.components().insertProjectBranch(project, b -> b.setBranchType(PULL_REQUEST));
690     ComponentDto pullRequestFile = db.components().insertComponent(newFileDto(pullRequest));
691     IssueDto pullRequestIssue = db.issues().insertIssue(rule, pullRequest, pullRequestFile);
692     allowAnyoneOnProjects(project);
693     indexIssuesAndViews();
694
695     SearchWsResponse result = ws.newRequest()
696       .setParam(PARAM_COMPONENT_KEYS, pullRequest.getKey())
697       .setParam(PARAM_PULL_REQUEST, pullRequest.getPullRequest())
698       .executeProtobuf(SearchWsResponse.class);
699
700     assertThat(result.getIssuesList())
701       .extracting(Issue::getKey, Issue::getComponent, Issue::getPullRequest)
702       .containsExactlyInAnyOrder(tuple(pullRequestIssue.getKey(), pullRequestFile.getKey(), pullRequestFile.getPullRequest()));
703     assertThat(result.getComponentsList())
704       .extracting(Issues.Component::getKey, Issues.Component::getPullRequest)
705       .containsExactlyInAnyOrder(
706         tuple(pullRequestFile.getKey(), pullRequestFile.getPullRequest()),
707         tuple(pullRequest.getKey(), pullRequest.getPullRequest()));
708   }
709
710   @Test
711   public void search_using_main_branch_name() {
712     RuleDefinitionDto rule = db.rules().insertIssueRule();
713     ComponentDto project = db.components().insertPublicProject();
714     ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
715     IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
716     allowAnyoneOnProjects(project);
717     indexIssuesAndViews();
718
719     SearchWsResponse result = ws.newRequest()
720       .setParam(PARAM_COMPONENT_KEYS, project.getKey())
721       .setParam(PARAM_BRANCH, "master")
722       .executeProtobuf(SearchWsResponse.class);
723
724     assertThat(result.getIssuesList())
725       .extracting(Issue::getKey, Issue::getComponent, Issue::hasBranch)
726       .containsExactlyInAnyOrder(tuple(projectIssue.getKey(), projectFile.getKey(), false));
727     assertThat(result.getComponentsList())
728       .extracting(Issues.Component::getKey, Issues.Component::hasBranch)
729       .containsExactlyInAnyOrder(
730         tuple(projectFile.getKey(), false),
731         tuple(project.getKey(), false));
732   }
733
734   @Test
735   public void does_not_return_branch_issues_on_not_contextualized_search() {
736     RuleDefinitionDto rule = db.rules().insertIssueRule();
737     ComponentDto project = db.components().insertPrivateProject();
738     ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
739     IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
740     ComponentDto branch = db.components().insertProjectBranch(project);
741     ComponentDto branchFile = db.components().insertComponent(newFileDto(branch));
742     IssueDto branchIssue = db.issues().insertIssue(rule, branch, branchFile);
743     allowAnyoneOnProjects(project);
744     indexIssuesAndViews();
745
746     SearchWsResponse result = ws.newRequest().executeProtobuf(SearchWsResponse.class);
747
748     assertThat(result.getIssuesList()).extracting(Issue::getKey)
749       .containsExactlyInAnyOrder(projectIssue.getKey())
750       .doesNotContain(branchIssue.getKey());
751   }
752
753   @Test
754   public void does_not_return_branch_issues_when_using_db_key() {
755     RuleDefinitionDto rule = db.rules().insertIssueRule();
756     ComponentDto project = db.components().insertPrivateProject();
757     ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
758     IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
759     ComponentDto branch = db.components().insertProjectBranch(project);
760     ComponentDto branchFile = db.components().insertComponent(newFileDto(branch));
761     IssueDto branchIssue = db.issues().insertIssue(rule, branch, branchFile);
762     allowAnyoneOnProjects(project);
763     indexIssues();
764
765     SearchWsResponse result = ws.newRequest()
766       .setParam(PARAM_COMPONENT_KEYS, branch.getDbKey())
767       .executeProtobuf(SearchWsResponse.class);
768
769     assertThat(result.getIssuesList()).isEmpty();
770   }
771
772   private void allowAnyoneOnProjects(ComponentDto... projects) {
773     userSession.registerComponents(projects);
774     Arrays.stream(projects).forEach(p -> permissionIndexer.allowOnlyAnyone(p));
775   }
776
777   private void allowAnyoneOnApplication(ComponentDto application, ComponentDto... projects) {
778     userSession.registerApplication(application);
779     Arrays.stream(projects).forEach(p -> permissionIndexer.allowOnlyAnyone(p));
780   }
781
782   private void indexIssues() {
783     issueIndexer.indexAllIssues();
784   }
785
786   private void indexIssuesAndViews() {
787     indexIssues();
788     viewIndexer.indexAll();
789   }
790 }